Merge pull request #36 from rmannibucau/rmannibucau/proposal-for-adapted-2

proposal for adapted API
diff --git a/README.md b/README.md
index 76fc50b..bb95ecf 100644
--- a/README.md
+++ b/README.md
@@ -233,19 +233,68 @@
 #### Adapting Annotated Types as Services
 
 A common scenario with OSGi CDI Portable Extensions is for extensions to adapt annotated types originating in the CDI Bundle as OSGi services (or with more service types).
+Common examples are the use cases relying on a whiteboard patterns. In such a case, services are deployed in the whiteboard at registration time.
+Using OSGi-CDI, you can fully use another programming model and hide OSGi service in a lot of cases.
+For instance, Aries-CDI uses that for servlet components where `@WebServlet` - and other servlet annotations - are translated to an OSGi service registration with the HTTP whiteboard properties on the fly through a CDI extension.
 
-Aries CDI's Extension SPI provides a convenience mechanism in the form of a carrier annotation `@AdaptedService` and a helper utility `Adapted.withServiceTypes(AnnotatedTypeConfigurator<X>, Class<?>...)`.
+Aries CDI's Extension SPI provides a convenience mechanism in the form of a carrier annotation `@AdaptedService` and a helper extensions utilities.
+It is composed of mainly two points:
 
-The following will make the annotated type produce a service of type `javax.servlet.Servlet`:
+1. `ProcessPotentialService` which is equivalent to `ProcessAnnotatedType` but it guarantees the underlying annotated type does not have `@Service` so that you can process the bean. If you do yourself the `@Service` presence check, you can ignore that event type. Note that you can use `org.apache.aries.cdi.extension.spi.adapt.FiltersOn` as the CDI `@WithAnnotations` to filter this event by annotations or type.
+2. `MergeServiceTypes` event which can be sent from the `BeanManager` to add service types to a bean.
+
+For `ProcessPotentialService` to be enabled, you must register the extension firing `RegisterExtension` event in `BeforeBeanDiscovery` event:
 
 ```java
-if (!Adapted.withServiceTypes(configurator, javax.servlet.Servlet.class)) {
-   // was not adapted because it was already marked with @Service
-   return;
+void register(@Observes final BeforeBeanDiscovery beforeBeanDiscovery, final BeanManager manager) {
+    manager.fireEvent(new RegisterExtension(this));
 }
 ```
 
+Assuming you have the following bean:
 
+```java
+@MyAutoRegistration
+public class MyService implements MyApi {
+    // ... MyApi impl
+}
+```
+
+You can write an extension grabbing all `@MyAutoRegistration` types to add them as services and register it in OSGi registry:
+
+```java
+public class MyComponentTypeExtension implements Extension {
+    void register(@Observes final BeforeBeanDiscovery beforeBeanDiscovery, final BeanManager manager) {
+        manager.fireEvent(new RegisterExtension(this));
+    }
+
+    void forceMyComponentTypeToBeAService(
+            @Observes @FilterOn(annotations = MyAutoRegistration.class, types = MyApi.class) ProcessPotentialService pps,
+            BeanManager beanManager) {
+        beanManager.fireEvent(MergeServiceTypes.forEvent(pat).withTypes(MyApi.class).build());
+    }
+}
+```
+
+Alternatively you can use the funcitonal style for that extension:
+
+```java
+public class MyComponentTypeExtension implements Extension {
+    void register(@Observes final BeforeBeanDiscovery beforeBeanDiscovery, final BeanManager manager) {
+        manager.fireEvent(new RegisterExtension(this)
+            .registerObserver()
+                .forTypes(MyApi.class)
+                .forAnnotations(MyAutoRegistration.class)
+                .execute((beanManager, processPotentialService) ->
+                    beanManager.fireEvent(MergeServiceTypes.forEvent(pat).withTypes(MyApi.class).build()))
+            .done());
+    }
+}
+```
+
+This is enough to let Aries-CDI registers the annotated type as a service (as if you would have `@Service(MyApi.class)`).
+
+IMPORTANT: only `BeanManager` injection is supported for this kind of lifecycle methods.
 
 The dependency for the Extension SPI is:
 
diff --git a/cdi-executable/owb-executable.bndrun b/cdi-executable/owb-executable.bndrun
index b2af497..69530e0 100644
--- a/cdi-executable/owb-executable.bndrun
+++ b/cdi-executable/owb-executable.bndrun
@@ -25,7 +25,6 @@
 	openwebbeans-spi;version='[2.0.13,2.0.14)',\
 	org.apache.aries.cdi.extender;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.extension.spi;version='[1.1.0,1.1.1)',\
-	org.apache.aries.cdi.owb;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.spi;version='[1.1.0,1.1.1)',\
 	org.apache.aries.spifly.dynamic.framework.extension;version='[1.2.3,1.2.4)',\
 	org.apache.felix.configadmin;version='[1.9.10,1.9.11)',\
@@ -43,4 +42,5 @@
 	org.apache.xbean.finder-shaded;version='[4.13.0,4.13.1)',\
 	org.osgi.service.cdi;version='[1.0.0,1.0.1)',\
 	org.osgi.util.function;version='[1.1.0,1.1.1)',\
-	org.osgi.util.promise;version='[1.1.0,1.1.1)'
+	org.osgi.util.promise;version='[1.1.0,1.1.1)',\
+	org.apache.aries.cdi.owb;version='[1.1.0,1.1.1)'
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/BundleContextExtension.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/BundleContextExtension.java
index f412d48..6d8975c 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/BundleContextExtension.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/BundleContextExtension.java
@@ -26,6 +26,10 @@
 
 public class BundleContextExtension implements Extension {
 
+	protected BundleContextExtension() { // for proxy
+		this(null);
+	}
+
 	public BundleContextExtension(BundleContext bundleContext) {
 		_bundleContext = bundleContext;
 	}
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ConfigurationExtension.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ConfigurationExtension.java
index c006aa5..0558cbe 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ConfigurationExtension.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ConfigurationExtension.java
@@ -37,6 +37,11 @@
 
 public class ConfigurationExtension  extends AbstractMap<String, Object> implements Configuration, Extension {
 
+	protected ConfigurationExtension() { // proxy
+		_containerState = null;
+		_configuration = null;
+	}
+
 	public ConfigurationExtension(ContainerState containerState) {
 		_containerState = containerState;
 
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ContainerBootstrap.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ContainerBootstrap.java
index e3ab0ed..2d0b8d1 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ContainerBootstrap.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ContainerBootstrap.java
@@ -185,6 +185,10 @@
 			new LoggerExtension(containerState),
 			Maps.of(Constants.SERVICE_ID, counter.decrementAndGet(),
 					Constants.SERVICE_DESCRIPTION, "Aries CDI LoggerExtension"));
+		initializer.addExtension(
+				new ServiceAdapterExtension(),
+				Maps.of(Constants.SERVICE_ID, counter.decrementAndGet(),
+						Constants.SERVICE_DESCRIPTION, "Aries CDI ServiceAdapterExtension"));
 
 		// Add extensions found from the bundle's class loader, such as those in the Bundle-ClassPath
 		ServiceLoader.load(Extension.class, containerState.classLoader()).forEach(extension ->
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/LoggerExtension.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/LoggerExtension.java
index 5e6dab6..d110de3 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/LoggerExtension.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/LoggerExtension.java
@@ -26,6 +26,10 @@
 
 public class LoggerExtension implements Extension {
 
+	protected LoggerExtension() { // for proxy
+		this(null);
+	}
+
 	public LoggerExtension(ContainerState containerState) {
 		_containerState = containerState;
 	}
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/RuntimeExtension.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/RuntimeExtension.java
index 777ac6a..f0474f2 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/RuntimeExtension.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/RuntimeExtension.java
@@ -3,7 +3,7 @@
  * 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
+*     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,
@@ -92,6 +92,15 @@
 
 public class RuntimeExtension implements Extension {
 
+	protected RuntimeExtension() { // for extension proxy
+		_containerState = null;
+		_log = null;
+		_configurationBuilder = null;
+		_singleBuilder = null;
+		_factoryBuilder = null;
+		_containerTemplate = null;
+	}
+
 	public RuntimeExtension(
 		ContainerState containerState,
 		ConfigurationListener.Builder configurationBuilder,
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ServiceAdapterExtension.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ServiceAdapterExtension.java
new file mode 100644
index 0000000..ca3dc47
--- /dev/null
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/ServiceAdapterExtension.java
@@ -0,0 +1,204 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.container.internal.container;
+
+import static java.util.Arrays.asList;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toList;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterDeploymentValidation;
+import javax.enterprise.inject.spi.Annotated;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
+
+import org.apache.aries.cdi.extension.spi.adapt.FiltersOn;
+import org.apache.aries.cdi.extension.spi.adapt.MergeServiceTypes;
+import org.apache.aries.cdi.extension.spi.adapt.ProcessPotentialService;
+import org.apache.aries.cdi.extension.spi.adapt.RegisterExtension;
+import org.apache.aries.cdi.extension.spi.annotation.AdaptedService;
+import org.osgi.service.cdi.annotations.Service;
+
+public class ServiceAdapterExtension implements Extension {
+	private static final Predicate<AnnotatedType<?>> ANNOTATED_TYPE_TRUE_PREDICATE = at -> true;
+
+	private boolean started;
+
+	private Collection<Entry<Predicate<AnnotatedType<?>>, BiConsumer<BeanManager, ProcessAnnotatedType<?>>>> forwardingObservers = new ArrayList<>();
+
+	void capturePotentialServiceObservers(@Observes final RegisterExtension registerExtension) {
+		if (started) {
+			throw new IllegalStateException("Container already started");
+		}
+
+		// declarative mode
+		forwardingObservers.addAll(forMethods(registerExtension.getExtension().getClass())
+				.map(method -> new SimpleImmutableEntry<>(registerExtension.getExtension(), method))
+				.filter(method -> Stream.of(method.getValue().getParameters())
+						.anyMatch(p -> p.isAnnotationPresent(Observes.class) && p.getType() == ProcessPotentialService.class))
+				.map(e -> new SimpleImmutableEntry<>(toPredicate(e.getValue()), toConsumer(e.getValue(), e.getKey())))
+				.collect(toList()));
+
+		// functional mode
+		forwardingObservers.addAll(registerExtension.getBuilders().stream()
+				.map(builder -> new SimpleImmutableEntry<>(
+						toPredicate(builder.getAnnotations(), builder.getTypes()),
+						(BiConsumer<BeanManager, ProcessAnnotatedType<?>>) (bm, pat) ->
+								builder.getConsumer().accept(bm, new ProcessPotentialService(pat))))
+				.collect(toList()));
+	}
+
+	<T> void forwardToObservers(@Observes final ProcessAnnotatedType<T> pat, final BeanManager beanManager) {
+		AnnotatedType<T> annotatedType;
+		if (!forwardingObservers.isEmpty() && !(annotatedType = pat.getAnnotatedType()).isAnnotationPresent(Service.class)) {
+			// simulate that but avoid a tons of events for all possible combinations of qualifiers which would be too slow
+			// beanManager.fireEvent(new ProcessPotentialService(pat), createAllPotentialQualifiers(pat));
+
+			forwardingObservers.stream()
+					.filter(predicateWithObserver -> predicateWithObserver.getKey().test(annotatedType))
+					.map(Entry::getValue)
+					.forEach(observer -> observer.accept(beanManager, pat));
+		}
+	}
+
+	void mergeAdaptedServiceTypes(@Observes final MergeServiceTypes mergeServiceTypes) {
+		if (started) {
+			throw new IllegalStateException("Container already started");
+		}
+
+		final AdaptedService adaptedService = mergeServiceTypes.getProcessAnnotatedType()
+				.getAnnotatedType().getAnnotation(AdaptedService.class);
+		final AnnotatedTypeConfigurator<?> configurator = mergeServiceTypes.getProcessAnnotatedType().configureAnnotatedType();
+
+		final Class<?>[] services;
+		if (adaptedService != null) {
+			configurator.remove(a -> a.annotationType() == AdaptedService.class);
+			services = Stream.concat(
+					Stream.of(mergeServiceTypes.getTypes()),
+					Stream.of(adaptedService.value()))
+					.distinct()
+					.toArray(Class[]::new);
+		} else {
+			services = mergeServiceTypes.getTypes();
+		}
+		configurator.add(AdaptedService.Literal.of(services));
+	}
+
+	void setStarted(@Observes final AfterDeploymentValidation afterDeploymentValidation) {
+		started = true;
+	}
+
+	// using reflection since we are too early in CDI lifecycle to use CDI model
+	private Predicate<AnnotatedType<?>> toPredicate(final Method method) {
+		return Stream.of(method.getParameters())
+				.filter(parameter -> parameter.isAnnotationPresent(Observes.class))
+				.findFirst()
+				.map(parameter -> parameter.getAnnotation(FiltersOn.class))
+				.map(filters -> toPredicate(asList(filters.annotations()), asList(filters.types())))
+				.orElse(ANNOTATED_TYPE_TRUE_PREDICATE);
+	}
+
+	private Predicate<AnnotatedType<?>> toPredicate(final Collection<Class<?>> annotations, final Collection<Class<?>> types) {
+		return filterWithAnnotations(annotations).and(filterWithTypes(types));
+	}
+
+	private BiConsumer<BeanManager, ProcessAnnotatedType<?>> toConsumer(final Method method, final Extension instance) {
+		final BiFunction<BeanManager, ProcessAnnotatedType<?>, Object>[] argsFactory = Stream.of(method.getParameters())
+				.map(parameter -> lookupMethod(method, parameter))
+				.toArray(BiFunction[]::new);
+		if (!method.isAccessible()) {
+			method.setAccessible(true);
+		}
+		return (bm, pat) -> {
+			try {
+				method.invoke(
+						instance,
+						Stream.of(argsFactory).map(fn -> fn.apply(bm, pat)).toArray(Object[]::new));
+			} catch (final IllegalAccessException e) {
+				throw new IllegalStateException(e);
+			} catch (final InvocationTargetException e) {
+				throw new IllegalStateException(e.getTargetException());
+			}
+		};
+	}
+
+	private BiFunction<BeanManager, ProcessAnnotatedType<?>, Object> lookupMethod(
+			final Method method, final Parameter parameter) {
+		if (BeanManager.class == parameter.getType()) {
+			return (bm, pat) -> bm;
+		}
+		if (ProcessPotentialService.class == parameter.getType()) {
+			return (bm, pat) -> new ProcessPotentialService(pat);
+		}
+		throw new IllegalArgumentException(
+				"Unsupported type: " + parameter.getType() + " on " + method);
+	}
+
+	private Predicate<AnnotatedType<?>> filterWithTypes(final Collection<Class<?>> filterOnTypes) {
+		return Optional.of(filterOnTypes)
+				.filter(this::shouldNotIgnore)
+				.map(types -> (Predicate<AnnotatedType<?>>) annotatedType -> types.stream()
+						.anyMatch(t -> annotatedType.getJavaClass().isAssignableFrom(t)))
+				.orElse(ANNOTATED_TYPE_TRUE_PREDICATE);
+	}
+
+	private Predicate<AnnotatedType<?>> filterWithAnnotations(final Collection<Class<?>> filterOnAnnotations) {
+		return Optional.of(filterOnAnnotations)
+				.filter(this::shouldNotIgnore)
+				.map(withAnnotations -> (Predicate<AnnotatedType<?>>) annotatedType -> Stream.of(
+						Stream.of(annotatedType.getAnnotations()), // class
+						annotatedType.getFields().stream().map(Annotated::getAnnotations), // fields
+						Stream.concat( // (constructors + methods) x (self + parameters)
+								annotatedType.getMethods().stream(),
+								annotatedType.getConstructors().stream())
+								.flatMap(m -> Stream.concat(
+										Stream.of(m.getAnnotations()),
+										m.getParameters().stream().map(Annotated::getAnnotations))))
+						.flatMap(identity())
+						.anyMatch(annotations -> annotations.stream().anyMatch(annotation ->
+								withAnnotations.stream().anyMatch(withAnnotation -> Stream.concat(
+										Stream.of(annotation.annotationType()),
+										Stream.of(annotation.annotationType().getAnnotations()).map(Annotation::annotationType))
+										.anyMatch(withAnnotation::isAssignableFrom)))))
+				.orElse(ANNOTATED_TYPE_TRUE_PREDICATE);
+	}
+
+	private boolean shouldNotIgnore(final Collection<Class<?>> annotations) {
+		return annotations.size() != 1 || FiltersOn.class != annotations.iterator().next();
+	}
+
+	private Stream<Method> forMethods(final Class<?> clazz) {
+		return clazz == Object.class || clazz == null ?
+				Stream.empty() :
+				Stream.concat(Stream.of(clazz.getDeclaredMethods()), forMethods(clazz.getSuperclass()));
+	}
+}
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/provider/SeContainerInitializer.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/provider/SeContainerInitializer.java
index 1c33bf4..48e4edf 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/provider/SeContainerInitializer.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/provider/SeContainerInitializer.java
@@ -3,7 +3,7 @@
  * 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
+*     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,
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/spi/ContainerListener.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/spi/ContainerListener.java
index c77f82e..dc2a8e8 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/spi/ContainerListener.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/spi/ContainerListener.java
@@ -3,7 +3,7 @@
  * 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
+*     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,
@@ -14,8 +14,8 @@
 package org.apache.aries.cdi.container.internal.spi;
 
 public interface ContainerListener {
-    void onStartSuccess();
-    void onStartError(Throwable error);
-    void onStopSuccess();
-    void onStopError(Throwable error);
+	void onStartSuccess();
+	void onStartError(Throwable error);
+	void onStopSuccess();
+	void onStopError(Throwable error);
 }
diff --git a/cdi-extension-el-jsp/src/main/java/org/apache/aries/cdi/extension/el/jsp/ELJSPExtension.java b/cdi-extension-el-jsp/src/main/java/org/apache/aries/cdi/extension/el/jsp/ELJSPExtension.java
index 3e3b89f..581c71c 100644
--- a/cdi-extension-el-jsp/src/main/java/org/apache/aries/cdi/extension/el/jsp/ELJSPExtension.java
+++ b/cdi-extension-el-jsp/src/main/java/org/apache/aries/cdi/extension/el/jsp/ELJSPExtension.java
@@ -51,6 +51,10 @@
 
 public class ELJSPExtension implements Extension {
 
+	protected ELJSPExtension() { // proxy
+		_bundle = null;
+	}
+
 	public ELJSPExtension(Bundle bundle) {
 		_bundle = bundle;
 	}
diff --git a/cdi-extension-jaxrs/src/main/java/org/apache/aries/cdi/extension/jaxrs/JaxrsCDIExtension.java b/cdi-extension-jaxrs/src/main/java/org/apache/aries/cdi/extension/jaxrs/JaxrsCDIExtension.java
index 8915d70..7b92941 100644
--- a/cdi-extension-jaxrs/src/main/java/org/apache/aries/cdi/extension/jaxrs/JaxrsCDIExtension.java
+++ b/cdi-extension-jaxrs/src/main/java/org/apache/aries/cdi/extension/jaxrs/JaxrsCDIExtension.java
@@ -2,9 +2,9 @@
  * 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
- *
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
  * 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.
@@ -24,10 +24,10 @@
 import javax.enterprise.event.Observes;
 import javax.enterprise.inject.spi.AfterDeploymentValidation;
 import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
 import javax.enterprise.inject.spi.DeploymentException;
 import javax.enterprise.inject.spi.Extension;
-import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.inject.spi.WithAnnotations;
 import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
 import javax.ws.rs.ApplicationPath;
 import javax.ws.rs.DELETE;
@@ -51,7 +51,10 @@
 import javax.ws.rs.ext.ReaderInterceptor;
 import javax.ws.rs.ext.WriterInterceptor;
 
-import org.apache.aries.cdi.extension.spi.adapt.Adapted;
+import org.apache.aries.cdi.extension.spi.adapt.FiltersOn;
+import org.apache.aries.cdi.extension.spi.adapt.MergeServiceTypes;
+import org.apache.aries.cdi.extension.spi.adapt.ProcessPotentialService;
+import org.apache.aries.cdi.extension.spi.adapt.RegisterExtension;
 import org.apache.aries.cdi.extra.propertytypes.JaxrsApplicationBase;
 import org.apache.aries.cdi.extra.propertytypes.JaxrsApplicationSelect;
 import org.apache.aries.cdi.extra.propertytypes.JaxrsExtension;
@@ -67,265 +70,159 @@
 public class JaxrsCDIExtension implements Extension {
 
 	private volatile Configuration configuration;
-	private final List<AnnotatedType<? extends Application>> applications = new CopyOnWriteArrayList<>();
+	private final List<AnnotatedType<?>> applications = new CopyOnWriteArrayList<>();
 
+	void register(@Observes final BeforeBeanDiscovery beforeBeanDiscovery, final BeanManager manager) {
+		manager.fireEvent(new RegisterExtension(this));
+	}
 
 	void getConfiguration(@Observes Configuration configuration) {
 		this.configuration = configuration;
 	}
 
 	void application(
-		@Observes @WithAnnotations(ApplicationPath.class)
-		ProcessAnnotatedType<? extends Application> pat) {
+			@Observes @FiltersOn(annotations = ApplicationPath.class)
+			ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends Application> annotatedType = pat.getAnnotatedType();
+		AnnotatedType<?> annotatedType = pat.getAnnotatedType();
 
 		applications.add(annotatedType);
 
-		AnnotatedTypeConfigurator<? extends Application> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, Application.class, true)) {
-			return;
-		}
-
+		commonProperties(pat, Application.class, true, beanManager);
 		if (!annotatedType.isAnnotationPresent(JaxrsApplicationBase.class)) {
-			configurator.add(
-				JaxrsApplicationBase.Literal.of(
-					annotatedType.getAnnotation(ApplicationPath.class).value()));
+			pat.configureAnnotatedType().add(
+					JaxrsApplicationBase.Literal.of(
+							annotatedType.getAnnotation(ApplicationPath.class).value()));
 		}
 	}
 
-	<X> void resource(
-		@Observes @WithAnnotations({Path.class, DELETE.class, GET.class, HEAD.class, OPTIONS.class, PATCH.class, POST.class, PUT.class})
-		ProcessAnnotatedType<X> pat) {
+	void resource(
+			@Observes
+			@FiltersOn(annotations = {Path.class, DELETE.class, GET.class, HEAD.class, OPTIONS.class, PATCH.class, POST.class, PUT.class})
+			ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<X> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<X> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, Object.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsResource.class)) {
-			configurator.add(JaxrsResource.Literal.INSTANCE);
+		commonProperties(pat, Object.class, false, beanManager);
+		if (!pat.getAnnotatedType().isAnnotationPresent(JaxrsResource.class)) {
+			pat.configureAnnotatedType().add(JaxrsResource.Literal.INSTANCE);
 		}
 	}
 
 	void containerRequestFilter(
-		@Observes ProcessAnnotatedType<? extends ContainerRequestFilter> pat) {
-
-		AnnotatedType<? extends ContainerRequestFilter> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends ContainerRequestFilter> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, ContainerRequestFilter.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+			@Observes @FiltersOn(types = ContainerRequestFilter.class) ProcessPotentialService pat, BeanManager beanManager) {
+		commonProperties(pat, ContainerRequestFilter.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	void containerResponseFilter(
-		@Observes ProcessAnnotatedType<? extends ContainerResponseFilter> pat) {
+			@Observes @FiltersOn(types = ContainerResponseFilter.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends ContainerResponseFilter> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends ContainerResponseFilter> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, ContainerResponseFilter.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+		commonProperties(pat, ContainerResponseFilter.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	void readerInterceptor(
-		@Observes ProcessAnnotatedType<? extends ReaderInterceptor> pat) {
+			@Observes @FiltersOn(types = ReaderInterceptor.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends ReaderInterceptor> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends ReaderInterceptor> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, ReaderInterceptor.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+		commonProperties(pat, ReaderInterceptor.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	void writerInterceptor(
-		@Observes ProcessAnnotatedType<? extends WriterInterceptor> pat) {
+			@Observes @FiltersOn(types = WriterInterceptor.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends WriterInterceptor> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends WriterInterceptor> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, WriterInterceptor.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+		commonProperties(pat, WriterInterceptor.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	@SuppressWarnings("rawtypes")
 	void messageBodyReader(
-		@Observes ProcessAnnotatedType<? extends MessageBodyReader> pat) {
+			@Observes @FiltersOn(types = MessageBodyReader.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends MessageBodyReader> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends MessageBodyReader> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, MessageBodyReader.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+		commonProperties(pat, MessageBodyReader.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	@SuppressWarnings("rawtypes")
 	void messageBodyWriter(
-		@Observes ProcessAnnotatedType<? extends MessageBodyWriter> pat) {
+			@Observes @FiltersOn(types = MessageBodyWriter.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends MessageBodyWriter> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends MessageBodyWriter> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, MessageBodyWriter.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+		commonProperties(pat, MessageBodyWriter.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	@SuppressWarnings("rawtypes")
 	void contextResolver(
-		@Observes ProcessAnnotatedType<? extends ContextResolver> pat) {
+			@Observes @FiltersOn(types = ContextResolver.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends ContextResolver> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends ContextResolver> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, ContextResolver.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+		commonProperties(pat, ContextResolver.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	@SuppressWarnings("rawtypes")
 	void exceptionMapper(
-		@Observes ProcessAnnotatedType<? extends ExceptionMapper> pat) {
+			@Observes @FiltersOn(types = ExceptionMapper.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends ExceptionMapper> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends ExceptionMapper> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, ExceptionMapper.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+		commonProperties(pat, ExceptionMapper.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	void paramConverterProvider(
-		@Observes ProcessAnnotatedType<? extends ParamConverterProvider> pat) {
+			@Observes @FiltersOn(types = ParamConverterProvider.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends ParamConverterProvider> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends ParamConverterProvider> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, ParamConverterProvider.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+		commonProperties(pat, ParamConverterProvider.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	void feature(
-		@Observes ProcessAnnotatedType<? extends Feature> pat) {
+			@Observes @FiltersOn(types = Feature.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends Feature> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<? extends Feature> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, Feature.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
-		}
+		commonProperties(pat, Feature.class, false, beanManager);
+		addJaxRsExtension(pat);
 	}
 
 	void dynamicFeature(
-		@Observes ProcessAnnotatedType<? extends DynamicFeature> pat) {
+			@Observes @FiltersOn(types = DynamicFeature.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends DynamicFeature> annotatedType = pat.getAnnotatedType();
+		commonProperties(pat, DynamicFeature.class, false, beanManager);
+		addJaxRsExtension(pat);
+	}
 
-		AnnotatedTypeConfigurator<? extends DynamicFeature> configurator = pat.configureAnnotatedType();
-
-		if (!commonProperties(annotatedType, configurator, DynamicFeature.class, false)) {
-			return;
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-			configurator.add(JaxrsExtension.Literal.INSTANCE);
+	private void addJaxRsExtension(final ProcessPotentialService pat) {
+		if (!pat.getAnnotatedType().isAnnotationPresent(JaxrsExtension.class)) {
+			pat.configureAnnotatedType().add(JaxrsExtension.Literal.INSTANCE);
 		}
 	}
 
 	/*
 	 * @return true if common properties were added (i.e. if no @Service was found)
 	 */
-	boolean commonProperties(
-		AnnotatedType<?> annotatedType, AnnotatedTypeConfigurator<?> configurator,
-		Class<?> serviceType, boolean application) {
-
-		if (!Adapted.withServiceTypes(configurator, serviceType)) {
-			return false;
-		}
-
+	private void commonProperties(
+			ProcessPotentialService pat, Class<?> serviceType, boolean application, BeanManager beanManager) {
+		beanManager.fireEvent(MergeServiceTypes.forEvent(pat).withTypes(serviceType).build());
+		final AnnotatedTypeConfigurator<?> configurator = pat.configureAnnotatedType();
+		final AnnotatedType<?> annotatedType = pat.getAnnotatedType();
 		if (!annotatedType.isAnnotationPresent(JaxrsName.class)) {
 			if (application) {
 				configurator.add(
-					JaxrsName.Literal.of(
-						ofNullable((String)configuration.get(JaxrsWhiteboardConstants.JAX_RS_NAME)).orElse(
-							JaxrsWhiteboardConstants.JAX_RS_DEFAULT_APPLICATION
+						JaxrsName.Literal.of(
+								ofNullable((String) configuration.get(JaxrsWhiteboardConstants.JAX_RS_NAME)).orElse(
+										JaxrsWhiteboardConstants.JAX_RS_DEFAULT_APPLICATION
+								)
 						)
-					)
 				);
-			}
-			else {
+			} else {
 				configurator.add(JaxrsName.Literal.of(annotatedType.getJavaClass().getSimpleName()));
 			}
 		}
 
 		if (!application && !annotatedType.isAnnotationPresent(JaxrsApplicationSelect.class)) {
-			ofNullable((String)configuration.get(JaxrsWhiteboardConstants.JAX_RS_APPLICATION_SELECT)).ifPresent(
-				select -> configurator.add(JaxrsApplicationSelect.Literal.of(select))
+			ofNullable((String) configuration.get(JaxrsWhiteboardConstants.JAX_RS_APPLICATION_SELECT)).ifPresent(
+					select -> configurator.add(JaxrsApplicationSelect.Literal.of(select))
 			);
 		}
 
 		if (!annotatedType.isAnnotationPresent(JaxrsExtensionSelect.class)) {
-			ofNullable((String[])configuration.get(JaxrsWhiteboardConstants.JAX_RS_EXTENSION_SELECT)).ifPresent(selects -> {
+			ofNullable((String[]) configuration.get(JaxrsWhiteboardConstants.JAX_RS_EXTENSION_SELECT)).ifPresent(selects -> {
 				if (selects.length > 0) {
 					configurator.add(JaxrsExtensionSelect.Literal.of(selects));
 				}
@@ -333,8 +230,8 @@
 		}
 
 		if (!annotatedType.isAnnotationPresent(JaxrsWhiteboardTarget.class)) {
-			ofNullable((String)configuration.get(JaxrsWhiteboardConstants.JAX_RS_WHITEBOARD_TARGET)).ifPresent(
-				target -> configurator.add(JaxrsWhiteboardTarget.Literal.of(target))
+			ofNullable((String) configuration.get(JaxrsWhiteboardConstants.JAX_RS_WHITEBOARD_TARGET)).ifPresent(
+					target -> configurator.add(JaxrsWhiteboardTarget.Literal.of(target))
 			);
 		}
 
@@ -345,15 +242,13 @@
 				configurator.add(ServiceInstance.Literal.of(ServiceScope.PROTOTYPE));
 			}
 		}
-
-		return true;
 	}
 
 	void afterDeploymentValidation(@Observes AfterDeploymentValidation adv) {
-		if (applications.size() > 1) {
+		if (applications.size() > 1) { // todo: revise that, it is not illegal and supported by cxf-cdi-extension
 			adv.addDeploymentProblem(
-				new DeploymentException(
-					"More than one javax.ws.rs.core.Application annotated types were found in the CDI bundle."));
+					new DeploymentException(
+							"More than one javax.ws.rs.core.Application annotated types were found in the CDI bundle."));
 		}
 	}
 
diff --git a/cdi-extension-mp-config/owb-itest.bndrun b/cdi-extension-mp-config/owb-itest.bndrun
index 93d9975..151611e 100644
--- a/cdi-extension-mp-config/owb-itest.bndrun
+++ b/cdi-extension-mp-config/owb-itest.bndrun
@@ -26,7 +26,8 @@
 	org.apache.aries.cdi.extension.mp-config-tests;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.extension.mp-config;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.extension.spi;version='[1.1.0,1.1.1)',\
-	org.apache.aries.cdi.owb;version='[1.1.0,1.1.1)',\
+	org.apache.aries.cdi.owb.spi;version='[1.1.0,1.1.1)',\
+    org.apache.aries.cdi.owb.core;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.spi;version='[1.1.0,1.1.1)',\
 	org.apache.aries.spifly.dynamic.framework.extension;version='[1.2.3,1.2.4)',\
 	org.apache.felix.configadmin;version='[1.9.10,1.9.11)',\
diff --git a/cdi-extension-mp-jwt-auth/owb-itest.bndrun b/cdi-extension-mp-jwt-auth/owb-itest.bndrun
index 2b9dd4e..e3fcbf7 100644
--- a/cdi-extension-mp-jwt-auth/owb-itest.bndrun
+++ b/cdi-extension-mp-jwt-auth/owb-itest.bndrun
@@ -33,7 +33,8 @@
 	org.apache.aries.cdi.extension.servlet.owb;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.extension.spi;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.extra;version='[1.1.0,1.1.1)',\
-	org.apache.aries.cdi.owb;version='[1.1.0,1.1.1)',\
+	org.apache.aries.cdi.owb.spi;version='[1.1.0,1.1.1)',\
+    org.apache.aries.cdi.owb.core;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.spi;version='[1.1.0,1.1.1)',\
 	org.apache.aries.jax.rs.whiteboard;version='[1.0.7,1.0.8)',\
 	org.apache.aries.spifly.dynamic.framework.extension;version='[1.2.3,1.2.4)',\
diff --git a/cdi-extension-mp-metrics/owb-itest.bndrun b/cdi-extension-mp-metrics/owb-itest.bndrun
index e7be03c..a16b8a7 100644
--- a/cdi-extension-mp-metrics/owb-itest.bndrun
+++ b/cdi-extension-mp-metrics/owb-itest.bndrun
@@ -27,7 +27,8 @@
 	org.apache.aries.cdi.extension.mp-metrics;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.extension.spi;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.extra;version='[1.1.0,1.1.1)',\
-	org.apache.aries.cdi.owb;version='[1.1.0,1.1.1)',\
+	org.apache.aries.cdi.owb.spi;version='[1.1.0,1.1.1)',\
+	org.apache.aries.cdi.owb.core;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.spi;version='[1.1.0,1.1.1)',\
 	org.apache.aries.jax.rs.whiteboard;version='[1.0.7,1.0.8)',\
 	org.apache.aries.spifly.dynamic.framework.extension;version='[1.2.3,1.2.4)',\
diff --git a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/BaseServletExtension.java b/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/BaseServletExtension.java
new file mode 100644
index 0000000..d025e6a
--- /dev/null
+++ b/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/BaseServletExtension.java
@@ -0,0 +1,215 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.extension.servlet.common;
+
+import static java.util.Optional.ofNullable;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Stream;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.BeforeShutdown;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.annotation.MultipartConfig;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.annotation.WebListener;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionIdListener;
+import javax.servlet.http.HttpSessionListener;
+
+import org.apache.aries.cdi.extension.spi.adapt.MergeServiceTypes;
+import org.apache.aries.cdi.extension.spi.adapt.ProcessPotentialService;
+import org.apache.aries.cdi.extension.spi.adapt.FiltersOn;
+import org.apache.aries.cdi.extension.spi.adapt.RegisterExtension;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardContextSelect;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterAsyncSupported;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterDispatcher;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterName;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterPattern;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterServlet;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardListener;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardServletAsyncSupported;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardServletMultipart;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardServletName;
+import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardServletPattern;
+import org.apache.aries.cdi.extra.propertytypes.ServiceDescription;
+import org.apache.aries.cdi.extra.propertytypes.ServiceRanking;
+import org.apache.aries.cdi.spi.configuration.Configuration;
+import org.osgi.framework.ServiceRegistration;
+
+public class BaseServletExtension implements Extension {
+	protected Configuration configuration;
+	protected volatile ServiceRegistration<?> _listenerRegistration;
+	protected final AtomicBoolean destroyed = new AtomicBoolean(false);
+
+	void register(@Observes final BeforeBeanDiscovery beforeBeanDiscovery, final BeanManager manager) {
+		manager.fireEvent(new RegisterExtension(this));
+	}
+
+	void setConfiguration(@Observes Configuration configuration) {
+		this.configuration = configuration;
+	}
+
+	void webFilter(@Observes @FiltersOn(annotations = WebFilter.class) ProcessPotentialService pat,
+				   BeanManager beanManager) {
+		beanManager.fireEvent(MergeServiceTypes.forEvent(pat).withTypes(Filter.class).build());
+		final AnnotatedTypeConfigurator<?> configurator = pat.configureAnnotatedType();
+		final AnnotatedType<?> annotatedType = pat.getAnnotatedType();
+
+		WebFilter webFilter = annotatedType.getAnnotation(WebFilter.class);
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardContextSelect.class)) {
+			ofNullable((String) configuration.get(HTTP_WHITEBOARD_CONTEXT_SELECT)).ifPresent(
+					select -> configurator.add(HttpWhiteboardContextSelect.Literal.of(select))
+			);
+		}
+
+		if (!annotatedType.isAnnotationPresent(ServiceDescription.class) && !webFilter.description().isEmpty()) {
+			configurator.add(ServiceDescription.Literal.of(webFilter.description()));
+		}
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardFilterName.class) && !webFilter.filterName().isEmpty()) {
+			configurator.add(HttpWhiteboardFilterName.Literal.of(webFilter.filterName()));
+		}
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardFilterServlet.class) && webFilter.servletNames().length > 0) {
+			configurator.add(HttpWhiteboardFilterServlet.Literal.of(webFilter.servletNames()));
+		}
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardFilterPattern.class)) {
+			if (webFilter.value().length > 0) {
+				configurator.add(HttpWhiteboardFilterPattern.Literal.of(webFilter.value()));
+			} else if (webFilter.urlPatterns().length > 0) {
+				configurator.add(HttpWhiteboardFilterPattern.Literal.of(webFilter.urlPatterns()));
+			}
+		}
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardFilterDispatcher.class) && webFilter.dispatcherTypes().length > 0) {
+			configurator.add(HttpWhiteboardFilterDispatcher.Literal.of(webFilter.dispatcherTypes()));
+		}
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardFilterAsyncSupported.class)) {
+			configurator.add(HttpWhiteboardFilterAsyncSupported.Literal.of(webFilter.asyncSupported()));
+		}
+	}
+
+	void webListener(@Observes @FiltersOn(annotations = WebListener.class) ProcessPotentialService pat,
+						 BeanManager beanManager) {
+		final AnnotatedType<?> annotatedType = pat.getAnnotatedType();
+		final Class<?> javaClass = annotatedType.getJavaClass();
+		final Class<?>[] serviceTypes = Stream.of(
+				ServletContextListener.class,
+				ServletContextAttributeListener.class,
+				ServletRequestListener.class,
+				ServletRequestAttributeListener.class,
+				HttpSessionListener.class,
+				HttpSessionAttributeListener.class,
+				HttpSessionIdListener.class)
+				.filter(c -> c.isAssignableFrom(javaClass))
+				.toArray(Class[]::new);
+
+		beanManager.fireEvent(MergeServiceTypes.forEvent(pat).withTypes(serviceTypes).build());
+
+		AnnotatedTypeConfigurator<?> configurator = pat.configureAnnotatedType();
+
+		WebListener webListener = annotatedType.getAnnotation(WebListener.class);
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardContextSelect.class)) {
+			ofNullable((String) configuration.get(HTTP_WHITEBOARD_CONTEXT_SELECT)).ifPresent(
+					select -> configurator.add(HttpWhiteboardContextSelect.Literal.of(select))
+			);
+		}
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardListener.class)) {
+			configurator.add(HttpWhiteboardListener.Literal.INSTANCE);
+		}
+
+		if (!annotatedType.isAnnotationPresent(ServiceDescription.class) && !webListener.value().isEmpty()) {
+			configurator.add(ServiceDescription.Literal.of(webListener.value()));
+		}
+	}
+
+	void webServlet(@Observes @FiltersOn(annotations = WebServlet.class) ProcessPotentialService pat,
+						BeanManager beanManager) {
+		beanManager.fireEvent(MergeServiceTypes.forEvent(pat).withTypes(Servlet.class).build());
+
+		final AnnotatedTypeConfigurator<?> configurator = pat.configureAnnotatedType();
+		final AnnotatedType<?> annotatedType = pat.getAnnotatedType();
+		WebServlet webServlet = annotatedType.getAnnotation(WebServlet.class);
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardContextSelect.class)) {
+			ofNullable((String) configuration.get(HTTP_WHITEBOARD_CONTEXT_SELECT)).ifPresent(
+					select -> configurator.add(HttpWhiteboardContextSelect.Literal.of(select))
+			);
+		}
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardServletName.class) && !webServlet.name().isEmpty()) {
+			configurator.add(HttpWhiteboardServletName.Literal.of(webServlet.name()));
+		}
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardServletPattern.class)) {
+			if (webServlet.value().length > 0) {
+				configurator.add(HttpWhiteboardServletPattern.Literal.of(webServlet.value()));
+			} else if (webServlet.urlPatterns().length > 0) {
+				configurator.add(HttpWhiteboardServletPattern.Literal.of(webServlet.urlPatterns()));
+			}
+		}
+
+		if (!annotatedType.isAnnotationPresent(ServiceRanking.class)) {
+			configurator.add(ServiceRanking.Literal.of(webServlet.loadOnStartup()));
+		}
+
+		// TODO Howto: INIT PARAMS ???
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardServletAsyncSupported.class)) {
+			configurator.add(HttpWhiteboardServletAsyncSupported.Literal.of(webServlet.asyncSupported()));
+		}
+
+		if (!annotatedType.isAnnotationPresent(ServiceDescription.class) && !webServlet.description().isEmpty()) {
+			configurator.add(ServiceDescription.Literal.of(webServlet.description()));
+		}
+
+		if (!annotatedType.isAnnotationPresent(HttpWhiteboardServletMultipart.class)) {
+			MultipartConfig multipartConfig = annotatedType.getAnnotation(MultipartConfig.class);
+
+			if (multipartConfig != null) {
+				configurator.add(HttpWhiteboardServletMultipart.Literal.of(true, multipartConfig.fileSizeThreshold(), multipartConfig.location(), multipartConfig.maxFileSize(), multipartConfig.maxRequestSize()));
+			}
+		}
+
+		// TODO HowTo: ServletSecurity ???
+	}
+
+	void beforeShutdown(@Observes BeforeShutdown bs) {
+		if (_listenerRegistration != null && !destroyed.get()) {
+			try {
+				_listenerRegistration.unregister();
+			} catch (IllegalStateException ise) {
+				// the service was already unregistered.
+			}
+		}
+	}
+}
diff --git a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebFilterProcessor.java b/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebFilterProcessor.java
deleted file mode 100644
index 6bb425b..0000000
--- a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebFilterProcessor.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * 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.extension.servlet.common;
-
-import static java.util.Optional.ofNullable;
-import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT;
-
-import javax.enterprise.inject.spi.AnnotatedType;
-import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
-import javax.servlet.Filter;
-import javax.servlet.annotation.WebFilter;
-
-import org.apache.aries.cdi.extension.spi.adapt.Adapted;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardContextSelect;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterAsyncSupported;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterDispatcher;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterName;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterPattern;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardFilterServlet;
-import org.apache.aries.cdi.extra.propertytypes.ServiceDescription;
-import org.apache.aries.cdi.spi.configuration.Configuration;
-
-public class WebFilterProcessor {
-
-	/**
-	 * Call this method from an observer defined as:
-	 * <pre>
-	 * &lt;X&gt; void webFilter(@Observes @WithAnnotations(WebFilter.class) ProcessAnnotatedType&lt;X&gt; pat) {
-	 *   new WebFilterProcessor().process(configuration, pat);
-	 * }
-	 * </pre>
-	 * @param <X>
-	 * @param pat
-	 */
-	public <X> void process(
-		Configuration configuration, ProcessAnnotatedType<X> pat) {
-
-		final AnnotatedType<X> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<X> configurator = pat.configureAnnotatedType();
-
-		if (!Adapted.withServiceTypes(configurator, Filter.class)) {
-			return;
-		}
-
-		WebFilter webFilter = annotatedType.getAnnotation(WebFilter.class);
-
-		if(!annotatedType.isAnnotationPresent(HttpWhiteboardContextSelect.class)) {
-			ofNullable((String)configuration.get(HTTP_WHITEBOARD_CONTEXT_SELECT)).ifPresent(
-				select -> configurator.add(HttpWhiteboardContextSelect.Literal.of(select))
-			);
-		}
-
-		if (!annotatedType.isAnnotationPresent(ServiceDescription.class) && !webFilter.description().isEmpty()) {
-			configurator.add(ServiceDescription.Literal.of(webFilter.description()));
-		}
-
-		if (!annotatedType.isAnnotationPresent(HttpWhiteboardFilterName.class) && !webFilter.filterName().isEmpty()) {
-			configurator.add(HttpWhiteboardFilterName.Literal.of(webFilter.filterName()));
-		}
-
-		if (!annotatedType.isAnnotationPresent(HttpWhiteboardFilterServlet.class) && webFilter.servletNames().length > 0) {
-			configurator.add(HttpWhiteboardFilterServlet.Literal.of(webFilter.servletNames()));
-		}
-
-		if (!annotatedType.isAnnotationPresent(HttpWhiteboardFilterPattern.class)) {
-			if (webFilter.value().length > 0) {
-				configurator.add(HttpWhiteboardFilterPattern.Literal.of(webFilter.value()));
-			}
-			else if (webFilter.urlPatterns().length > 0) {
-				configurator.add(HttpWhiteboardFilterPattern.Literal.of(webFilter.urlPatterns()));
-			}
-		}
-
-		if (!annotatedType.isAnnotationPresent(HttpWhiteboardFilterDispatcher.class) && webFilter.dispatcherTypes().length > 0) {
-			configurator.add(HttpWhiteboardFilterDispatcher.Literal.of(webFilter.dispatcherTypes()));
-		}
-
-		if(!annotatedType.isAnnotationPresent(HttpWhiteboardFilterAsyncSupported.class)) {
-			configurator.add(HttpWhiteboardFilterAsyncSupported.Literal.of(webFilter.asyncSupported()));
-		}
-	}
-
-}
diff --git a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebListenerProcessor.java b/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebListenerProcessor.java
deleted file mode 100644
index ac2dfa0..0000000
--- a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebListenerProcessor.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * 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.extension.servlet.common;
-
-import static java.util.Optional.ofNullable;
-import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.enterprise.inject.spi.AnnotatedType;
-import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
-import javax.servlet.annotation.WebListener;
-
-import org.apache.aries.cdi.extension.spi.adapt.Adapted;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardContextSelect;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardListener;
-import org.apache.aries.cdi.extra.propertytypes.ServiceDescription;
-import org.apache.aries.cdi.spi.configuration.Configuration;
-
-public class WebListenerProcessor {
-
-	/**
-	 * Call this method from an observer defined as:
-	 * <pre>
-	 * &lt;X&gt; void webListener(@Observes @WithAnnotations(WebListener.class) ProcessAnnotatedType&lt;X&gt; pat) {
-	 *   new WebListenerProcessor().process(configuration, pat);
-	 * }
-	 * </pre>
-	 * @param <X>
-	 * @param pat
-	 */
-	public <X> void process(
-		Configuration configuration, ProcessAnnotatedType<X> pat) {
-
-		final AnnotatedType<X> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<X> configurator = pat.configureAnnotatedType();
-
-		Set<Class<?>> serviceTypes = new HashSet<>();
-
-		Class<X> javaClass = annotatedType.getJavaClass();
-
-		if (javax.servlet.ServletContextListener.class.isAssignableFrom(javaClass)) {
-			serviceTypes.add(javax.servlet.ServletContextListener.class);
-		}
-		if (javax.servlet.ServletContextAttributeListener.class.isAssignableFrom(javaClass)) {
-			serviceTypes.add(javax.servlet.ServletContextAttributeListener.class);
-		}
-		if (javax.servlet.ServletRequestListener.class.isAssignableFrom(javaClass)) {
-			serviceTypes.add(javax.servlet.ServletRequestListener.class);
-		}
-		if (javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(javaClass)) {
-			serviceTypes.add(javax.servlet.ServletRequestAttributeListener.class);
-		}
-		if (javax.servlet.http.HttpSessionListener.class.isAssignableFrom(javaClass)) {
-			serviceTypes.add(javax.servlet.http.HttpSessionListener.class);
-		}
-		if (javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(javaClass)) {
-			serviceTypes.add(javax.servlet.http.HttpSessionAttributeListener.class);
-		}
-		if (javax.servlet.http.HttpSessionIdListener.class.isAssignableFrom(javaClass)) {
-			serviceTypes.add(javax.servlet.http.HttpSessionIdListener.class);
-		}
-
-		if (!Adapted.withServiceTypes(configurator, serviceTypes)) {
-			return;
-		}
-
-		WebListener webListener = annotatedType.getAnnotation(WebListener.class);
-
-		if(!annotatedType.isAnnotationPresent(HttpWhiteboardContextSelect.class)) {
-			ofNullable((String)configuration.get(HTTP_WHITEBOARD_CONTEXT_SELECT)).ifPresent(
-				select -> configurator.add(HttpWhiteboardContextSelect.Literal.of(select))
-			);
-		}
-
-		if(!annotatedType.isAnnotationPresent(HttpWhiteboardListener.class)) {
-			configurator.add(HttpWhiteboardListener.Literal.INSTANCE);
-		}
-
-		if (!annotatedType.isAnnotationPresent(ServiceDescription.class) && !webListener.value().isEmpty()) {
-			configurator.add(ServiceDescription.Literal.of(webListener.value()));
-		}
-	}
-
-}
diff --git a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebServletProcessor.java b/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebServletProcessor.java
deleted file mode 100644
index 590e805..0000000
--- a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebServletProcessor.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * 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.extension.servlet.common;
-
-import static java.util.Optional.ofNullable;
-import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT;
-
-import javax.enterprise.inject.spi.AnnotatedType;
-import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
-import javax.servlet.Servlet;
-import javax.servlet.annotation.MultipartConfig;
-import javax.servlet.annotation.WebServlet;
-
-import org.apache.aries.cdi.extension.spi.adapt.Adapted;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardContextSelect;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardServletAsyncSupported;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardServletMultipart;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardServletName;
-import org.apache.aries.cdi.extra.propertytypes.HttpWhiteboardServletPattern;
-import org.apache.aries.cdi.extra.propertytypes.ServiceDescription;
-import org.apache.aries.cdi.extra.propertytypes.ServiceRanking;
-import org.apache.aries.cdi.spi.configuration.Configuration;
-
-public class WebServletProcessor {
-
-	/**
-	 * Call this method from an observer defined as:
-	 * <pre>
-	 * &lt;X&gt; void webServlet(@Observes @WithAnnotations(WebServlet.class) ProcessAnnotatedType&lt;X&gt; pat) {
-	 *   new WebServletProcessor().process(configuration, pat);
-	 * }
-	 * </pre>
-	 * @param <X>
-	 * @param pat
-	 */
-	public <X> void process(
-		Configuration configuration, ProcessAnnotatedType<X> pat) {
-
-		final AnnotatedType<X> annotatedType = pat.getAnnotatedType();
-
-		AnnotatedTypeConfigurator<X> configurator = pat.configureAnnotatedType();
-
-		if (!Adapted.withServiceTypes(configurator, Servlet.class)) {
-			return;
-		}
-
-		WebServlet webServlet = annotatedType.getAnnotation(WebServlet.class);
-
-		if(!annotatedType.isAnnotationPresent(HttpWhiteboardContextSelect.class)) {
-			ofNullable((String)configuration.get(HTTP_WHITEBOARD_CONTEXT_SELECT)).ifPresent(
-				select -> configurator.add(HttpWhiteboardContextSelect.Literal.of(select))
-			);
-		}
-
-		if (!annotatedType.isAnnotationPresent(HttpWhiteboardServletName.class) && !webServlet.name().isEmpty()) {
-			configurator.add(HttpWhiteboardServletName.Literal.of(webServlet.name()));
-		}
-
-		if(!annotatedType.isAnnotationPresent(HttpWhiteboardServletPattern.class)) {
-			if (webServlet.value().length > 0) {
-				configurator.add(HttpWhiteboardServletPattern.Literal.of(webServlet.value()));
-			}
-			else if (webServlet.urlPatterns().length > 0) {
-				configurator.add(HttpWhiteboardServletPattern.Literal.of(webServlet.urlPatterns()));
-			}
-		}
-
-		if (!annotatedType.isAnnotationPresent(ServiceRanking.class)) {
-			configurator.add(ServiceRanking.Literal.of(webServlet.loadOnStartup()));
-		}
-
-		// TODO Howto: INIT PARAMS ???
-
-		if (!annotatedType.isAnnotationPresent(HttpWhiteboardServletAsyncSupported.class)) {
-			configurator.add(HttpWhiteboardServletAsyncSupported.Literal.of(webServlet.asyncSupported()));
-		}
-
-		if (!annotatedType.isAnnotationPresent(ServiceDescription.class) && !webServlet.description().isEmpty()) {
-			configurator.add(ServiceDescription.Literal.of(webServlet.description()));
-		}
-
-		if (!annotatedType.isAnnotationPresent(HttpWhiteboardServletMultipart.class)) {
-			MultipartConfig multipartConfig = annotatedType.getAnnotation(MultipartConfig.class);
-
-			if (multipartConfig != null) {
-				configurator.add(HttpWhiteboardServletMultipart.Literal.of(true, multipartConfig.fileSizeThreshold(), multipartConfig.location(), multipartConfig.maxFileSize(), multipartConfig.maxRequestSize()));
-			}
-		}
-
-		// TODO HowTo: ServletSecurity ???
-	}
-
-}
diff --git a/cdi-extension-servlet-owb/pom.xml b/cdi-extension-servlet-owb/pom.xml
index 4a709f0..5293e69 100644
--- a/cdi-extension-servlet-owb/pom.xml
+++ b/cdi-extension-servlet-owb/pom.xml
@@ -64,6 +64,11 @@
 		</dependency>
 		<dependency>
 			<groupId>org.apache.aries.cdi</groupId>
+			<artifactId>org.apache.aries.cdi.owb</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.aries.cdi</groupId>
 			<artifactId>org.apache.aries.cdi.extra</artifactId>
 			<version>${project.version}</version>
 		</dependency>
diff --git a/cdi-extension-servlet-owb/src/main/java/org/apache/aries/cdi/extension/servlet/owb/OWBServletExtension.java b/cdi-extension-servlet-owb/src/main/java/org/apache/aries/cdi/extension/servlet/owb/OWBServletExtension.java
index 5dec26d..1ed2c4f 100644
--- a/cdi-extension-servlet-owb/src/main/java/org/apache/aries/cdi/extension/servlet/owb/OWBServletExtension.java
+++ b/cdi-extension-servlet-owb/src/main/java/org/apache/aries/cdi/extension/servlet/owb/OWBServletExtension.java
@@ -2,9 +2,9 @@
  * 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
- *
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
  * 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.
@@ -27,46 +27,46 @@
 import java.lang.reflect.Proxy;
 import java.util.Dictionary;
 import java.util.Hashtable;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.annotation.Priority;
 import javax.enterprise.event.Observes;
 import javax.enterprise.inject.spi.AfterDeploymentValidation;
 import javax.enterprise.inject.spi.BeanManager;
-import javax.enterprise.inject.spi.BeforeShutdown;
-import javax.enterprise.inject.spi.Extension;
-import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.inject.spi.WithAnnotations;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.ServletRequestListener;
-import javax.servlet.annotation.WebFilter;
-import javax.servlet.annotation.WebListener;
-import javax.servlet.annotation.WebServlet;
 import javax.servlet.http.HttpSessionListener;
 
-import org.apache.aries.cdi.extension.servlet.common.WebFilterProcessor;
-import org.apache.aries.cdi.extension.servlet.common.WebListenerProcessor;
-import org.apache.aries.cdi.extension.servlet.common.WebServletProcessor;
-import org.apache.aries.cdi.spi.configuration.Configuration;
+import org.apache.aries.cdi.extension.servlet.common.BaseServletExtension;
+import org.apache.aries.cdi.owb.spi.StartObjectSupplier;
 import org.apache.webbeans.config.WebBeansContext;
 import org.apache.webbeans.spi.ContainerLifecycle;
 import org.apache.webbeans.web.lifecycle.test.MockServletContext;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
 
 @SuppressWarnings("serial")
-public class OWBServletExtension extends ServletContextEvent implements Extension {
+public class OWBServletExtension extends BaseServletExtension implements StartObjectSupplier {
 
 	private final BundleContext bundleContext;
 	private final ServletContext proxyContext;
+	private final ServletContextEvent startEvent;
 	private volatile ServletContext delegateContext;
-	volatile Configuration configuration;
+
+	protected OWBServletExtension() { // proxy
+		bundleContext = null;
+		proxyContext = null;
+		startEvent = null;
+	}
 
 	public OWBServletExtension(Bundle bundle) {
-		super(new MockServletContext());
+		this.startEvent = new ServletContextEvent(new MockServletContext()) {
+			@Override
+			public ServletContext getServletContext() {
+				return proxyContext;
+			}
+		};
 
 		this.bundleContext = bundle.getBundleContext();
 
@@ -75,9 +75,8 @@
 				new Class<?>[]{ServletContext.class},
 				(proxy, method, args) -> {
 					try {
-						return method.invoke(ofNullable(delegateContext).orElseGet(OWBServletExtension.super::getServletContext), args);
-					}
-					catch (final InvocationTargetException ite) {
+						return method.invoke(ofNullable(delegateContext).orElseGet(startEvent::getServletContext), args);
+					} catch (final InvocationTargetException ite) {
 						throw ite.getTargetException();
 					}
 				}));
@@ -87,34 +86,9 @@
 		this.delegateContext = delegateContext;
 	}
 
-	public ServletContext getOriginal() {
-		return super.getServletContext();
-	}
-
-	@Override
-	public ServletContext getServletContext() {
-		return proxyContext;
-	}
-
-	void setConfiguration(@Observes Configuration configuration) {
-		this.configuration = configuration;
-	}
-
-	<X> void webFilter(@Observes @WithAnnotations(WebFilter.class) ProcessAnnotatedType<X> pat) {
-		new WebFilterProcessor().process(configuration, pat);
-	}
-
-	<X> void webListener(@Observes @WithAnnotations(WebListener.class) ProcessAnnotatedType<X> pat) {
-		new WebListenerProcessor().process(configuration, pat);
-	}
-
-	<X> void webServlet(@Observes @WithAnnotations(WebServlet.class) ProcessAnnotatedType<X> pat) {
-		new WebServletProcessor().process(configuration, pat);
-	}
-
 	void afterDeploymentValidation(
-		@Observes @Priority(LIBRARY_AFTER + 800)
-		AfterDeploymentValidation adv, BeanManager beanManager) {
+			@Observes @Priority(LIBRARY_AFTER + 800)
+					AfterDeploymentValidation adv, BeanManager beanManager) {
 
 		Dictionary<String, Object> properties = new Hashtable<>();
 		properties.put(SERVICE_DESCRIPTION, "Aries CDI - HTTP Portable Extension for OpenWebBeans");
@@ -124,28 +98,19 @@
 		properties.put(SERVICE_RANKING, Integer.MAX_VALUE - 100);
 
 		_listenerRegistration = bundleContext.registerService(
-			LISTENER_CLASSES, new CdiListener(WebBeansContext.currentInstance()), properties);
+				LISTENER_CLASSES, new CdiListener(WebBeansContext.currentInstance()), properties);
 	}
 
-	void beforeShutdown(@Observes BeforeShutdown bs) {
-		if (_listenerRegistration != null && !destroyed.get()) {
-			try {
-				_listenerRegistration.unregister();
-			}
-			catch (IllegalStateException ise) {
-				// the service was already unregistered.
-			}
-		}
-	}
-
-	private static final String[] LISTENER_CLASSES = new String[] {
-		ServletContextListener.class.getName(),
-		ServletRequestListener.class.getName(),
-		HttpSessionListener.class.getName()
+	private static final String[] LISTENER_CLASSES = new String[]{
+			ServletContextListener.class.getName(),
+			ServletRequestListener.class.getName(),
+			HttpSessionListener.class.getName()
 	};
 
-	private volatile ServiceRegistration<?> _listenerRegistration;
-	private final AtomicBoolean destroyed = new AtomicBoolean(false);
+	@Override
+	public Object getStartObject() {
+		return startEvent;
+	}
 
 	private class CdiListener extends org.apache.webbeans.servlet.WebBeansConfigurationListener {
 		private final WebBeansContext webBeansContext;
@@ -162,8 +127,8 @@
 			setDelegate(realSC);
 
 			// propagate attributes from the temporary sc
-			list(getOriginal().getAttributeNames()).forEach(
-				attr -> realSC.setAttribute(attr, getOriginal().getAttribute(attr)));
+			list(startEvent.getServletContext().getAttributeNames()).forEach(
+					attr -> realSC.setAttribute(attr, startEvent.getServletContext().getAttribute(attr)));
 
 			realSC.setAttribute(BundleContext.class.getName(), bundleContext);
 			realSC.setAttribute(WebBeansContext.class.getName(), webBeansContext);
@@ -179,8 +144,7 @@
 		public void contextDestroyed(ServletContextEvent sce) {
 			try {
 				super.contextDestroyed(sce);
-			}
-			finally {
+			} finally {
 				destroyed.set(true);
 			}
 		}
diff --git a/cdi-extension-servlet-weld/src/main/java/org/apache/aries/cdi/extension/servlet/weld/WeldServletExtension.java b/cdi-extension-servlet-weld/src/main/java/org/apache/aries/cdi/extension/servlet/weld/WeldServletExtension.java
index a91af52..e76e6fe 100644
--- a/cdi-extension-servlet-weld/src/main/java/org/apache/aries/cdi/extension/servlet/weld/WeldServletExtension.java
+++ b/cdi-extension-servlet-weld/src/main/java/org/apache/aries/cdi/extension/servlet/weld/WeldServletExtension.java
@@ -25,7 +25,6 @@
 import java.util.Hashtable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.annotation.Priority;
 import javax.enterprise.event.Observes;
@@ -34,55 +33,31 @@
 import javax.enterprise.inject.spi.AnnotatedType;
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
-import javax.enterprise.inject.spi.BeforeShutdown;
-import javax.enterprise.inject.spi.Extension;
 import javax.enterprise.inject.spi.InjectionTargetFactory;
-import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.inject.spi.WithAnnotations;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.ServletRequestEvent;
 import javax.servlet.ServletRequestListener;
-import javax.servlet.annotation.WebFilter;
-import javax.servlet.annotation.WebListener;
-import javax.servlet.annotation.WebServlet;
 import javax.servlet.http.HttpSessionEvent;
 import javax.servlet.http.HttpSessionListener;
 
-import org.apache.aries.cdi.extension.servlet.common.WebFilterProcessor;
-import org.apache.aries.cdi.extension.servlet.common.WebListenerProcessor;
-import org.apache.aries.cdi.extension.servlet.common.WebServletProcessor;
-import org.apache.aries.cdi.spi.configuration.Configuration;
+import org.apache.aries.cdi.extension.servlet.common.BaseServletExtension;
 import org.jboss.weld.module.web.servlet.WeldInitialListener;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
 
-public class WeldServletExtension implements Extension {
+public class WeldServletExtension extends BaseServletExtension {
 
 	private final BundleContext bundleContext;
-	volatile Configuration configuration;
+
+	protected WeldServletExtension() { // proxy
+		bundleContext = null;
+	}
 
 	public WeldServletExtension(Bundle bundle) {
 		this.bundleContext = bundle.getBundleContext();
 	}
 
-	void setConfiguration(@Observes Configuration configuration) {
-		this.configuration = configuration;
-	}
-
-	<X> void webFilter(@Observes @WithAnnotations(WebFilter.class) ProcessAnnotatedType<X> pat) {
-		new WebFilterProcessor().process(configuration, pat);
-	}
-
-	<X> void webListener(@Observes @WithAnnotations(WebListener.class) ProcessAnnotatedType<X> pat) {
-		new WebListenerProcessor().process(configuration, pat);
-	}
-
-	<X> void webServlet(@Observes @WithAnnotations(WebServlet.class) ProcessAnnotatedType<X> pat) {
-		new WebServletProcessor().process(configuration, pat);
-	}
-
 	void afterDeploymentValidation(
 		@Observes @Priority(LIBRARY_AFTER + 800)
 		AfterDeploymentValidation adv, BeanManager beanManager) {
@@ -111,26 +86,12 @@
 			LISTENER_CLASSES, new ListenerWrapper<>(initialListener), properties);
 	}
 
-	void beforeShutdown(@Observes BeforeShutdown bs) {
-		if (_listenerRegistration != null && !destroyed.get()) {
-			try {
-				_listenerRegistration.unregister();
-			}
-			catch (IllegalStateException ise) {
-				// the service was already unregistered.
-			}
-		}
-	}
-
 	private static final String[] LISTENER_CLASSES = new String[] {
 		ServletContextListener.class.getName(),
 		ServletRequestListener.class.getName(),
 		HttpSessionListener.class.getName()
 	};
 
-	private volatile ServiceRegistration<?> _listenerRegistration;
-	private final AtomicBoolean destroyed = new AtomicBoolean(false);
-
 	public static class Ready {}
 
 	private class ListenerWrapper<T extends HttpSessionListener & ServletContextListener & ServletRequestListener>
diff --git a/cdi-extension-spi/pom.xml b/cdi-extension-spi/pom.xml
index f010ece..3f1ff20 100644
--- a/cdi-extension-spi/pom.xml
+++ b/cdi-extension-spi/pom.xml
@@ -59,6 +59,10 @@
 			<artifactId>geronimo-jcdi_2.0_spec</artifactId>
 		</dependency>
 		<dependency>
+			<groupId>org.apache.geronimo.specs</groupId>
+			<artifactId>geronimo-atinject_1.0_spec</artifactId>
+		</dependency>
+		<dependency>
 			<groupId>org.osgi</groupId>
 			<artifactId>org.osgi.service.cdi</artifactId>
 		</dependency>
diff --git a/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/Adapted.java b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/Adapted.java
deleted file mode 100644
index 9f29f05..0000000
--- a/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/Adapted.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2018). All Rights Reserved.
- *
- * 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.extension.spi.adapt;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
-
-import org.apache.aries.cdi.extension.spi.annotation.AdaptedService;
-import org.osgi.service.cdi.annotations.Service;
-
-public class Adapted {
-
-	private Adapted() {
-		//
-	}
-
-	/**
-	 * Adapt the annotated type associated with the configurator with additional
-	 * types in order to publish OSGi services with those types.
-	 * <p>
-	 * The annotated type will not be adapted if it is already annotated with {@link Service @Service}.
-	 *
-	 * @param <X> the type of the annotated type
-	 * @param configurator the configurator
-	 * @param serviceTypes the additional service types
-	 * @return true if the annotated type was adapted
-	 */
-	public static <X> boolean withServiceTypes(AnnotatedTypeConfigurator<X> configurator, Collection<Class<?>> serviceTypes) {
-		return withServiceTypes(configurator, serviceTypes, false);
-	}
-
-	/**
-	 * Adapt the annotated type associated with the configurator with additional
-	 * types in order to publish OSGi services with those types.
-	 * <p>
-	 * The annotated type will not be adapted if it is already annotated with {@link Service @Service}.
-	 *
-	 * @param <X> the type of the annotated type
-	 * @param configurator the configurator
-	 * @param serviceTypes the additional service types
-	 * @return true if the annotated type was adapted
-	 */
-	public static <X> boolean withServiceTypes(AnnotatedTypeConfigurator<X> configurator, Class<?>... serviceTypes) {
-		return withServiceTypes(configurator, Arrays.asList(serviceTypes), false);
-	}
-
-	/**
-	 * Adapt the annotated type associated with the configurator with additional
-	 * types in order to publish OSGi services with those types.
-	 * <p>
-	 * The annotated type will not be adapted if it is already annotated with {@link Service @Service}.
-	 *
-	 * @param <X> the type of the annotated type
-	 * @param configurator the configurator
-	 * @param serviceTypes the additional service types
-	 * @param replace if true do not merge with previous types
-	 * @return true if the annotated type was adapted
-	 */
-	public static <X> boolean withServiceTypes(AnnotatedTypeConfigurator<X> configurator, Collection<Class<?>> serviceTypes, boolean replace) {
-		if (configurator.getAnnotated().isAnnotationPresent(Service.class)) {
-			return false;
-		}
-
-		Set<Class<?>> servicesSet = new HashSet<>(serviceTypes);
-
-		AdaptedService adaptedService = configurator.getAnnotated().getAnnotation(AdaptedService.class);
-
-		if (adaptedService != null) {
-			configurator.remove(adaptedService::equals);
-			if (!replace) {
-				servicesSet.addAll(Arrays.asList(adaptedService.value()));
-			}
-		}
-
-		configurator.add(
-			AdaptedService.Literal.of(servicesSet.toArray(new Class<?>[0])));
-
-		return true;
-	}
-
-}
diff --git a/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/FiltersOn.java b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/FiltersOn.java
new file mode 100644
index 0000000..af826ae
--- /dev/null
+++ b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/FiltersOn.java
@@ -0,0 +1,57 @@
+/**
+ * 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.extension.spi.adapt;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.enterprise.util.AnnotationLiteral;
+
+/**
+ * Close of {@link javax.enterprise.inject.spi.WithAnnotations} but for {@link ProcessPotentialService} event.
+ * Enables to filter the observed annotated types.
+ */
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface FiltersOn {
+	/**
+	 * @return the annotations the {@link javax.enterprise.inject.spi.ProcessAnnotatedType} should get filtered for.
+	 */
+	Class<? extends Annotation>[] annotations() default {FiltersOn.class};
+
+	/**
+	 * @return the types to filter the event on using {@link Class#isAssignableFrom(Class)}.
+	 */
+	Class<?>[] types() default {FiltersOn.class};
+
+	class Literal extends AnnotationLiteral<FiltersOn> implements FiltersOn {
+		public static final Literal INSTANCE = new Literal();
+
+		private final Class[] defaultArray = new Class[0];
+
+		@Override
+		public Class<? extends Annotation>[] annotations() {
+			return defaultArray;
+		}
+
+		@Override
+		public Class<?>[] types() {
+			return defaultArray;
+		}
+	}
+}
+
diff --git a/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/MergeServiceTypes.java b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/MergeServiceTypes.java
new file mode 100644
index 0000000..7901481
--- /dev/null
+++ b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/MergeServiceTypes.java
@@ -0,0 +1,79 @@
+/**
+ * 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.extension.spi.adapt;
+
+import java.util.Arrays;
+
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+
+/**
+ * If fired (using the {@link javax.enterprise.inject.spi.BeanManager}) during a {@link ProcessAnnotatedType} event,
+ * it will configure the annotated type to add {@link org.apache.aries.cdi.extension.spi.annotation.AdaptedService}
+ * with the referenced types - potentially merged with already existing ones.
+ */
+public class MergeServiceTypes {
+	private final Class<?>[] types;
+	private final ProcessAnnotatedType<?> processAnnotatedType;
+
+	private MergeServiceTypes(final ProcessAnnotatedType<?> processAnnotatedType,
+							 final Class<?>... types) {
+		this.types = types;
+		this.processAnnotatedType = processAnnotatedType;
+	}
+
+	public Class<?>[] getTypes() {
+		return types;
+	}
+
+	public ProcessAnnotatedType<?> getProcessAnnotatedType() {
+		return processAnnotatedType;
+	}
+
+	@Override
+	public String toString() {
+		return "MergeServiceTypes{types=" + Arrays.toString(types) + '}';
+	}
+
+	public static Builder forEvent(final ProcessAnnotatedType<?> pat) {
+		return new Builder(pat);
+	}
+
+	public static Builder forEvent(final ProcessPotentialService pat) {
+		return new Builder(pat.getProcessAnnotatedType());
+	}
+
+	public static final class Builder {
+		private final ProcessAnnotatedType<?> processAnnotatedType;
+		private Class<?>[] types;
+
+		private Builder(final ProcessAnnotatedType<?> processAnnotatedType) {
+			if (processAnnotatedType == null) {
+				throw new IllegalArgumentException("processAnnotatedType can't be null");
+			}
+			this.processAnnotatedType = processAnnotatedType;
+		}
+
+		public Builder withTypes(final Class<?>... types) {
+			this.types = types;
+			return this;
+		}
+
+		public MergeServiceTypes build() {
+			if (types == null) {
+				throw new IllegalArgumentException("No types set");
+			}
+			return new MergeServiceTypes(processAnnotatedType, types);
+		}
+	}
+}
diff --git a/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/ProcessPotentialService.java b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/ProcessPotentialService.java
new file mode 100644
index 0000000..998e1bc
--- /dev/null
+++ b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/ProcessPotentialService.java
@@ -0,0 +1,49 @@
+/**
+ * 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.extension.spi.adapt;
+
+import static java.util.Objects.requireNonNull;
+
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
+
+/**
+ * Can be observed in an extension to customize an annotated type without
+ * {@link org.osgi.service.cdi.annotations.Service} marker.
+ */
+public class ProcessPotentialService {
+	private final ProcessAnnotatedType<?> processAnnotatedType;
+
+	public ProcessPotentialService(final ProcessAnnotatedType<?> processAnnotatedType) {
+		this.processAnnotatedType = requireNonNull(processAnnotatedType, "processAnnotatedType can't be null");
+	}
+
+	public ProcessAnnotatedType<?> getProcessAnnotatedType() {
+		return processAnnotatedType;
+	}
+
+	public AnnotatedType<?> getAnnotatedType() {
+		return processAnnotatedType.getAnnotatedType();
+	}
+
+	public AnnotatedTypeConfigurator<?> configureAnnotatedType() {
+		return processAnnotatedType.configureAnnotatedType();
+	}
+
+	@Override
+	public String toString() {
+		return "ProcessPotentialService{processAnnotatedType=" + processAnnotatedType + '}';
+	}
+}
diff --git a/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/RegisterExtension.java b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/RegisterExtension.java
new file mode 100644
index 0000000..45dc444
--- /dev/null
+++ b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/RegisterExtension.java
@@ -0,0 +1,109 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.extension.spi.adapt;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static java.util.Collections.unmodifiableList;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+
+/**
+ * If fired (using the {@link javax.enterprise.inject.spi.BeanManager})
+ * during a {@link javax.enterprise.inject.spi.BeforeBeanDiscovery} event,
+ * it will enable to filter {@link ProcessAnnotatedType} event and convert them to {@link ProcessPotentialService}
+ * event with {@link FiltersOn} support.
+ */
+public class RegisterExtension {
+	private final Extension extension;
+	private final Collection<ObserverBuilder> builders = new ArrayList<>();
+
+	public RegisterExtension(final Extension extension) {
+		this.extension = extension;
+	}
+
+	public Extension getExtension() {
+		return extension;
+	}
+
+	public Collection<ObserverBuilder> getBuilders() {
+		return builders;
+	}
+
+	public ObserverBuilder registerObserver() {
+		return new ObserverBuilder(this);
+	}
+
+	public static class ObserverBuilder {
+		private final RegisterExtension parent;
+
+		// defaults aligned on the annotation to have a single impl
+		private List<Class<?>> types = new ArrayList<>(singletonList(FiltersOn.class));
+		private List<Class<? extends Annotation>> annotations = new ArrayList<>(singletonList(FiltersOn.class));
+		private BiConsumer<BeanManager, ProcessPotentialService> consumer;
+
+		private ObserverBuilder(final RegisterExtension parent) {
+			this.parent = parent;
+		}
+
+		public ObserverBuilder forTypes(final Class<?>... types) {
+			if (types.length > 0) {
+				this.types.remove(FiltersOn.class);
+			}
+			this.types.addAll(asList(types));
+			return this;
+		}
+
+		public ObserverBuilder forAnnotations(final Class<? extends Annotation>... annotations) {
+			if (annotations.length > 0) {
+				this.annotations.remove(FiltersOn.class);
+			}
+			this.annotations.addAll(asList(annotations));
+			return this;
+		}
+
+		public ObserverBuilder execute(final BiConsumer<BeanManager, ProcessPotentialService> consumer) {
+			this.consumer = consumer;
+			return this;
+		}
+
+		public Collection<Class<?>> getTypes() {
+			return unmodifiableList(types);
+		}
+
+		public Collection<Class<?>> getAnnotations() {
+			return unmodifiableList(annotations);
+		}
+
+		public BiConsumer<BeanManager, ProcessPotentialService> getConsumer() {
+			return consumer;
+		}
+
+		public RegisterExtension done() {
+			if (consumer == null) {
+				throw new IllegalArgumentException("No consumer registered on observer builder");
+			}
+			parent.builders.add(this);
+			return parent;
+		}
+	}
+}
diff --git a/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/annotation/AdaptedService.java b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/annotation/AdaptedService.java
index b7a22fc..35479d2 100644
--- a/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/annotation/AdaptedService.java
+++ b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/annotation/AdaptedService.java
@@ -37,16 +37,16 @@
 	/**
 	 * Support inline instantiation of the {@link AdaptedService} annotation.
 	 */
-	public static final class Literal extends AnnotationLiteral<AdaptedService>
+	final class Literal extends AnnotationLiteral<AdaptedService>
 			implements AdaptedService {
 
 		private static final long serialVersionUID = 1L;
 
 		/**
-		 * @param interfaces
+		 * @param interfaces value.
 		 * @return instance of {@link AdaptedService}
 		 */
-		public static final Literal of(Class<?>[] interfaces) {
+		public static Literal of(Class<?>[] interfaces) {
 			return new Literal(interfaces);
 		}
 
diff --git a/cdi-itests/owb-itest.bndrun b/cdi-itests/owb-itest.bndrun
index c614a4d..edef0c5 100644
--- a/cdi-itests/owb-itest.bndrun
+++ b/cdi-itests/owb-itest.bndrun
@@ -33,7 +33,6 @@
 	org.apache.aries.cdi.extension.spi;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.extra;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.itests;version='[1.1.0,1.1.1)',\
-	org.apache.aries.cdi.owb;version='[1.1.0,1.1.1)',\
 	org.apache.aries.cdi.spi;version='[1.1.0,1.1.1)',\
 	org.apache.aries.jax.rs.whiteboard;version='[1.0.6,1.0.7)',\
 	org.apache.aries.jndi.api;version='[1.1.0,1.1.1)',\
@@ -64,4 +63,5 @@
 	org.osgi.test.common;version='[1.0.0,1.0.1)',\
 	org.osgi.test.junit4;version='[1.0.0,1.0.1)',\
 	org.osgi.util.function;version='[1.1.0,1.1.1)',\
-	org.osgi.util.promise;version='[1.1.0,1.1.1)'
+	org.osgi.util.promise;version='[1.1.0,1.1.1)',\
+	org.apache.aries.cdi.owb;version='[1.1.0,1.1.1)'
diff --git a/cdi-owb/pom.xml b/cdi-owb/pom.xml
index e4de12d..14b1fcd 100644
--- a/cdi-owb/pom.xml
+++ b/cdi-owb/pom.xml
@@ -52,7 +52,6 @@
 				<configuration>
 					<bnd><![CDATA[
 						-cdiannotations:
-						-noclassforname: true
 					]]></bnd>
 				</configuration>
 			</plugin>
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/Activator.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/Activator.java
similarity index 97%
rename from cdi-owb/src/main/java/org/apache/aries/cdi/owb/Activator.java
rename to cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/Activator.java
index 91e8fb3..9680f5f 100644
--- a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/Activator.java
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/Activator.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package org.apache.aries.cdi.owb;
+package org.apache.aries.cdi.owb.core;
 
 import static org.osgi.framework.Constants.BUNDLE_ACTIVATOR;
 import static org.osgi.framework.Constants.SERVICE_DESCRIPTION;
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/CdiScannerService.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/CdiScannerService.java
similarity index 97%
rename from cdi-owb/src/main/java/org/apache/aries/cdi/owb/CdiScannerService.java
rename to cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/CdiScannerService.java
index 0a6bc04..0274fec 100644
--- a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/CdiScannerService.java
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/CdiScannerService.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package org.apache.aries.cdi.owb;
+package org.apache.aries.cdi.owb.core;
 
 import static java.util.Collections.emptySet;
 
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OSGiDefiningClassService.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OSGiDefiningClassService.java
similarity index 98%
rename from cdi-owb/src/main/java/org/apache/aries/cdi/owb/OSGiDefiningClassService.java
rename to cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OSGiDefiningClassService.java
index 8186eb7..a04ae37 100644
--- a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OSGiDefiningClassService.java
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OSGiDefiningClassService.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.aries.cdi.owb;
+package org.apache.aries.cdi.owb.core;
 
 import java.lang.reflect.Modifier;
 
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBCDIContainerInitializer.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OWBCDIContainerInitializer.java
similarity index 92%
rename from cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBCDIContainerInitializer.java
rename to cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OWBCDIContainerInitializer.java
index fc665d7..1b34f7b 100644
--- a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBCDIContainerInitializer.java
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OWBCDIContainerInitializer.java
@@ -12,11 +12,11 @@
  * limitations under the License.
  */
 
-package org.apache.aries.cdi.owb;
+package org.apache.aries.cdi.owb.core;
 
+import static java.util.Comparator.comparing;
 import static java.util.Objects.requireNonNull;
 import static org.osgi.framework.namespace.PackageNamespace.PACKAGE_NAMESPACE;
-import static org.osgi.service.cdi.CDIConstants.CDI_EXTENSION_PROPERTY;
 
 import java.io.IOException;
 import java.lang.annotation.Annotation;
@@ -39,6 +39,7 @@
 import javax.enterprise.inject.spi.Extension;
 import javax.enterprise.util.TypeLiteral;
 
+import org.apache.aries.cdi.owb.spi.StartObjectSupplier;
 import org.apache.aries.cdi.spi.CDIContainerInitializer;
 import org.apache.aries.cdi.spi.loader.SpiLoader;
 import org.apache.webbeans.config.WebBeansContext;
@@ -152,17 +153,17 @@
 			// This Extension will have properties:
 			//    osgi.cdi.extension = aries.cdi.http
 			//    aries.cdi.http.provider = OpenWebBeans
-			extensions.entrySet().stream().filter(
-				e -> "aries.cdi.http".equals(e.getValue().get(CDI_EXTENSION_PROPERTY)) &&
-					"OpenWebBeans".equalsIgnoreCase(String.valueOf(e.getValue().get("aries.cdi.http.provider")))
-			).findFirst().ifPresent(entry -> {
-				// The service properties of the extension should list any properties needed
-				// to configure OWB for web support.
-				properties.putAll(entry.getValue());
+			extensions.entrySet().stream()
+					.filter(it -> StartObjectSupplier.class.isInstance(it.getKey()))
+					.max(comparing(it -> StartObjectSupplier.class.cast(it.getKey()).ordinal()))
+					.ifPresent(entry -> {
+						// The service properties of the extension should list any properties needed
+						// to configure OWB for web support.
+						properties.putAll(entry.getValue());
 
-				// The extension itself implements ServletContextEvent so set as the start object
-				startObject = entry.getKey();
-			});
+						// Extract the start instance to ensure it works with the configured services (properties)
+						startObject = StartObjectSupplier.class.cast(entry.getKey()).getStartObject();
+					});
 
 			bootstrap = new WebBeansContext(services, properties) {
 				private final ExtensionLoader overridenExtensionLoader = new ExtensionLoader(this) {
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBCDIContainerInitializerFactory.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OWBCDIContainerInitializerFactory.java
similarity index 97%
rename from cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBCDIContainerInitializerFactory.java
rename to cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OWBCDIContainerInitializerFactory.java
index db10ecd..c8f973b 100644
--- a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBCDIContainerInitializerFactory.java
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OWBCDIContainerInitializerFactory.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package org.apache.aries.cdi.owb;
+package org.apache.aries.cdi.owb.core;
 
 import org.apache.aries.cdi.spi.CDIContainerInitializer;
 import org.osgi.framework.Bundle;
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OsgiApplicationBoundaryService.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OsgiApplicationBoundaryService.java
similarity index 97%
rename from cdi-owb/src/main/java/org/apache/aries/cdi/owb/OsgiApplicationBoundaryService.java
rename to cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OsgiApplicationBoundaryService.java
index b3985f9..b254bdb 100644
--- a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OsgiApplicationBoundaryService.java
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/OsgiApplicationBoundaryService.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.aries.cdi.owb;
+package org.apache.aries.cdi.owb.core;
 
 import org.apache.webbeans.spi.ApplicationBoundaryService;
 
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/package-info.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/package-info.java
similarity index 95%
rename from cdi-owb/src/main/java/org/apache/aries/cdi/owb/package-info.java
rename to cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/package-info.java
index 5e523d8..25a6297 100644
--- a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/package-info.java
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/core/package-info.java
@@ -17,4 +17,4 @@
 	namespace = org.osgi.namespace.service.ServiceNamespace.SERVICE_NAMESPACE
 )
 @org.osgi.service.cdi.annotations.RequireCDIImplementation
-package org.apache.aries.cdi.owb;
+package org.apache.aries.cdi.owb.core;
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/spi/StartObjectSupplier.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/spi/StartObjectSupplier.java
new file mode 100644
index 0000000..eeebcfb
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/spi/StartObjectSupplier.java
@@ -0,0 +1,22 @@
+/**
+ * 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.owb.spi;
+
+public interface StartObjectSupplier<T> {
+	T getStartObject();
+
+	default int ordinal() {
+		return 0;
+	}
+}
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/package-info.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/spi/package-info.java
similarity index 72%
copy from cdi-owb/src/main/java/org/apache/aries/cdi/owb/package-info.java
copy to cdi-owb/src/main/java/org/apache/aries/cdi/owb/spi/package-info.java
index 5e523d8..4dfef30 100644
--- a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/package-info.java
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/spi/package-info.java
@@ -12,9 +12,8 @@
  * limitations under the License.
  */
 
-@org.osgi.annotation.bundle.Capability(
-	attribute = "objectClass:List<String>=org.apache.aries.cdi.spi.CDIContainerInitializer",
-	namespace = org.osgi.namespace.service.ServiceNamespace.SERVICE_NAMESPACE
-)
+@Export
 @org.osgi.service.cdi.annotations.RequireCDIImplementation
-package org.apache.aries.cdi.owb;
+package org.apache.aries.cdi.owb.spi;
+
+import org.osgi.annotation.bundle.Export;
\ No newline at end of file