migrated API rework
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/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..0842a0e 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
@@ -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
index 8a5669f..c867a6f 100644
--- 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
@@ -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.
@@ -14,42 +14,191 @@
 
 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 boolean started;
+    private static final Predicate<AnnotatedType<?>> ANNOTATED_TYPE_TRUE_PREDICATE = at -> true;
 
-	<T> void onMergeServiceTypes(@Observes final MergeServiceTypes<T> mergeServiceTypes) {
-		if (started) {
-			throw new IllegalStateException("Container already started");
-		}
+    private boolean started;
 
-		final AdaptedService adaptedService = mergeServiceTypes.getProcessAnnotatedType()
-				.getAnnotatedType().getAnnotation(AdaptedService.class);
-		final AnnotatedTypeConfigurator<T> configurator = mergeServiceTypes.getProcessAnnotatedType().configureAnnotatedType();
+    private Collection<Entry<Predicate<AnnotatedType<?>>, BiConsumer<BeanManager, ProcessAnnotatedType<?>>>> forwardingObservers = new ArrayList<>();
 
-		final Class<?>[] services;
-		if (adaptedService != null) {
-			configurator.remove(a -> a.annotationType() == AdaptedService.class);
-			services = Stream.concat(
-					Stream.of(mergeServiceTypes.getTypes()),
-					Stream.of(adaptedService.value()))
-					.toArray(Class[]::new);
-		} else {
-			services = mergeServiceTypes.getTypes();
-		}
-		configurator.add(AdaptedService.Literal.of(services));
-	}
+    void capturePotentialServiceObservers(@Observes final RegisterExtension registerExtension) {
+        if (started) {
+            throw new IllegalStateException("Container already started");
+        }
 
-	void started(@Observes final AfterDeploymentValidation afterDeploymentValidation) {
-		started = true;
-	}
+        // 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-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 b63748d..3a3603f 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.
@@ -14,13 +14,10 @@
 
 package org.apache.aries.cdi.extension.jaxrs;
 
-import static java.util.Optional.empty;
-import static java.util.Optional.of;
 import static java.util.Optional.ofNullable;
 
 import java.lang.annotation.Annotation;
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.enterprise.context.Dependent;
@@ -28,10 +25,9 @@
 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;
@@ -55,7 +51,10 @@
 import javax.ws.rs.ext.ReaderInterceptor;
 import javax.ws.rs.ext.WriterInterceptor;
 
+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;
@@ -65,249 +64,192 @@
 import org.apache.aries.cdi.extra.propertytypes.JaxrsWhiteboardTarget;
 import org.apache.aries.cdi.spi.configuration.Configuration;
 import org.osgi.service.cdi.ServiceScope;
-import org.osgi.service.cdi.annotations.Service;
 import org.osgi.service.cdi.annotations.ServiceInstance;
 import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
 
 public class JaxrsCDIExtension implements Extension {
 
-	private volatile Configuration configuration;
-	private final List<AnnotatedType<? extends Application>> applications = new CopyOnWriteArrayList<>();
+    private volatile Configuration configuration;
+    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 getConfiguration(@Observes Configuration configuration) {
+        this.configuration = configuration;
+    }
 
-	void application(
-		@Observes @WithAnnotations(ApplicationPath.class)
-		ProcessAnnotatedType<? extends Application> pat, BeanManager beanManager) {
+    void application(
+            @Observes @FiltersOn(annotations = ApplicationPath.class)
+            ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends Application> annotatedType = pat.getAnnotatedType();
+        AnnotatedType<?> annotatedType = pat.getAnnotatedType();
 
-		applications.add(annotatedType);
+        applications.add(annotatedType);
 
-		commonProperties(pat, Application.class, true, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsApplicationBase.class)) {
-				configurator.add(
-						JaxrsApplicationBase.Literal.of(
-								annotatedType.getAnnotation(ApplicationPath.class).value()));
-			}
-		});
-	}
+        commonProperties(pat, Application.class, true, beanManager);
+        if (!annotatedType.isAnnotationPresent(JaxrsApplicationBase.class)) {
+            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, BeanManager beanManager) {
+    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();
+        commonProperties(pat, Object.class, false, beanManager);
+        if (!pat.getAnnotatedType().isAnnotationPresent(JaxrsResource.class)) {
+            pat.configureAnnotatedType().add(JaxrsResource.Literal.INSTANCE);
+        }
+    }
 
-		commonProperties(pat, Object.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsResource.class)) {
-				configurator.add(JaxrsResource.Literal.INSTANCE);
-			}
-		});
-	}
+    void containerRequestFilter(
+            @Observes @FiltersOn(types = ContainerRequestFilter.class) ProcessPotentialService pat, BeanManager beanManager) {
+        commonProperties(pat, ContainerRequestFilter.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-	void containerRequestFilter(
-		@Observes ProcessAnnotatedType<? extends ContainerRequestFilter> pat, BeanManager beanManager) {
+    void containerResponseFilter(
+            @Observes @FiltersOn(types = ContainerResponseFilter.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends ContainerRequestFilter> annotatedType = pat.getAnnotatedType();
+        commonProperties(pat, ContainerResponseFilter.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-		commonProperties(pat, ContainerRequestFilter.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
+    void readerInterceptor(
+            @Observes @FiltersOn(types = ReaderInterceptor.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-	void containerResponseFilter(
-		@Observes ProcessAnnotatedType<? extends ContainerResponseFilter> pat, BeanManager beanManager) {
+        commonProperties(pat, ReaderInterceptor.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-		AnnotatedType<? extends ContainerResponseFilter> annotatedType = pat.getAnnotatedType();
+    void writerInterceptor(
+            @Observes @FiltersOn(types = WriterInterceptor.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		commonProperties(pat, ContainerResponseFilter.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
+        commonProperties(pat, WriterInterceptor.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-	void readerInterceptor(
-		@Observes ProcessAnnotatedType<? extends ReaderInterceptor> pat, BeanManager beanManager) {
+    @SuppressWarnings("rawtypes")
+    void messageBodyReader(
+            @Observes @FiltersOn(types = MessageBodyReader.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends ReaderInterceptor> annotatedType = pat.getAnnotatedType();
+        commonProperties(pat, MessageBodyReader.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-		commonProperties(pat, ReaderInterceptor.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
+    @SuppressWarnings("rawtypes")
+    void messageBodyWriter(
+            @Observes @FiltersOn(types = MessageBodyWriter.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-	void writerInterceptor(
-		@Observes ProcessAnnotatedType<? extends WriterInterceptor> pat, BeanManager beanManager) {
+        commonProperties(pat, MessageBodyWriter.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-		AnnotatedType<? extends WriterInterceptor> annotatedType = pat.getAnnotatedType();
+    @SuppressWarnings("rawtypes")
+    void contextResolver(
+            @Observes @FiltersOn(types = ContextResolver.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		commonProperties(pat, WriterInterceptor.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
+        commonProperties(pat, ContextResolver.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-	@SuppressWarnings("rawtypes")
-	void messageBodyReader(
-		@Observes ProcessAnnotatedType<? extends MessageBodyReader> pat, BeanManager beanManager) {
+    @SuppressWarnings("rawtypes")
+    void exceptionMapper(
+            @Observes @FiltersOn(types = ExceptionMapper.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		AnnotatedType<? extends MessageBodyReader> annotatedType = pat.getAnnotatedType();
+        commonProperties(pat, ExceptionMapper.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-		commonProperties(pat, MessageBodyReader.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
+    void paramConverterProvider(
+            @Observes @FiltersOn(types = ParamConverterProvider.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-	@SuppressWarnings("rawtypes")
-	void messageBodyWriter(
-		@Observes ProcessAnnotatedType<? extends MessageBodyWriter> pat, BeanManager beanManager) {
+        commonProperties(pat, ParamConverterProvider.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-		AnnotatedType<? extends MessageBodyWriter> annotatedType = pat.getAnnotatedType();
+    void feature(
+            @Observes @FiltersOn(types = Feature.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-		commonProperties(pat, MessageBodyWriter.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
+        commonProperties(pat, Feature.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-		});
-	}
+    void dynamicFeature(
+            @Observes @FiltersOn(types = DynamicFeature.class) ProcessPotentialService pat, BeanManager beanManager) {
 
-	@SuppressWarnings("rawtypes")
-	void contextResolver(
-		@Observes ProcessAnnotatedType<? extends ContextResolver> pat, BeanManager beanManager) {
+        commonProperties(pat, DynamicFeature.class, false, beanManager);
+        addJaxRsExtension(pat);
+    }
 
-		AnnotatedType<? extends ContextResolver> annotatedType = pat.getAnnotatedType();
+    private void addJaxRsExtension(final ProcessPotentialService pat) {
+        if (!pat.getAnnotatedType().isAnnotationPresent(JaxrsExtension.class)) {
+            pat.configureAnnotatedType().add(JaxrsExtension.Literal.INSTANCE);
+        }
+    }
 
-		commonProperties(pat, ContextResolver.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
+    /*
+     * @return true if common properties were added (i.e. if no @Service was found)
+     */
+    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
+                                )
+                        )
+                );
+            } else {
+                configurator.add(JaxrsName.Literal.of(annotatedType.getJavaClass().getSimpleName()));
+            }
+        }
 
-	@SuppressWarnings("rawtypes")
-	void exceptionMapper(
-		@Observes ProcessAnnotatedType<? extends ExceptionMapper> pat, BeanManager beanManager) {
+        if (!application && !annotatedType.isAnnotationPresent(JaxrsApplicationSelect.class)) {
+            ofNullable((String) configuration.get(JaxrsWhiteboardConstants.JAX_RS_APPLICATION_SELECT)).ifPresent(
+                    select -> configurator.add(JaxrsApplicationSelect.Literal.of(select))
+            );
+        }
 
-		AnnotatedType<? extends ExceptionMapper> annotatedType = pat.getAnnotatedType();
+        if (!annotatedType.isAnnotationPresent(JaxrsExtensionSelect.class)) {
+            ofNullable((String[]) configuration.get(JaxrsWhiteboardConstants.JAX_RS_EXTENSION_SELECT)).ifPresent(selects -> {
+                if (selects.length > 0) {
+                    configurator.add(JaxrsExtensionSelect.Literal.of(selects));
+                }
+            });
+        }
 
-		commonProperties(pat, ExceptionMapper.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
+        if (!annotatedType.isAnnotationPresent(JaxrsWhiteboardTarget.class)) {
+            ofNullable((String) configuration.get(JaxrsWhiteboardConstants.JAX_RS_WHITEBOARD_TARGET)).ifPresent(
+                    target -> configurator.add(JaxrsWhiteboardTarget.Literal.of(target))
+            );
+        }
 
-	void paramConverterProvider(
-		@Observes ProcessAnnotatedType<? extends ParamConverterProvider> pat, BeanManager beanManager) {
+        if (!annotatedType.isAnnotationPresent(ServiceInstance.class)) {
+            Class<? extends Annotation> beanScope = Util.beanScope(annotatedType, Dependent.class);
 
-		AnnotatedType<? extends ParamConverterProvider> annotatedType = pat.getAnnotatedType();
+            if (Dependent.class.equals(beanScope)) {
+                configurator.add(ServiceInstance.Literal.of(ServiceScope.PROTOTYPE));
+            }
+        }
+    }
 
-		commonProperties(pat, ParamConverterProvider.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
-
-	void feature(
-		@Observes ProcessAnnotatedType<? extends Feature> pat, BeanManager beanManager) {
-
-		AnnotatedType<? extends Feature> annotatedType = pat.getAnnotatedType();
-
-		commonProperties(pat, Feature.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
-
-	void dynamicFeature(
-		@Observes ProcessAnnotatedType<? extends DynamicFeature> pat, BeanManager beanManager) {
-
-		AnnotatedType<? extends DynamicFeature> annotatedType = pat.getAnnotatedType();
-
-		commonProperties(pat, DynamicFeature.class, false, beanManager).ifPresent(configurator -> {
-			if (!annotatedType.isAnnotationPresent(JaxrsExtension.class)) {
-				configurator.add(JaxrsExtension.Literal.INSTANCE);
-			}
-		});
-	}
-
-	/*
-	 * @return true if common properties were added (i.e. if no @Service was found)
-	 */
-	private <X> Optional<AnnotatedTypeConfigurator<X>> commonProperties(
-			ProcessAnnotatedType<X> pat, Class<?> serviceType, boolean application, BeanManager beanManager) {
-		if (pat.getAnnotatedType().isAnnotationPresent(Service.class)) {
-			return empty();
-		}
-		beanManager.fireEvent(new MergeServiceTypes<>(pat, serviceType));
-		final AnnotatedTypeConfigurator<X> 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
-								)
-						)
-				);
-			}
-			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))
-			);
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsExtensionSelect.class)) {
-			ofNullable((String[])configuration.get(JaxrsWhiteboardConstants.JAX_RS_EXTENSION_SELECT)).ifPresent(selects -> {
-				if (selects.length > 0) {
-					configurator.add(JaxrsExtensionSelect.Literal.of(selects));
-				}
-			});
-		}
-
-		if (!annotatedType.isAnnotationPresent(JaxrsWhiteboardTarget.class)) {
-			ofNullable((String)configuration.get(JaxrsWhiteboardConstants.JAX_RS_WHITEBOARD_TARGET)).ifPresent(
-					target -> configurator.add(JaxrsWhiteboardTarget.Literal.of(target))
-			);
-		}
-
-		if (!annotatedType.isAnnotationPresent(ServiceInstance.class)) {
-			Class<? extends Annotation> beanScope = Util.beanScope(annotatedType, Dependent.class);
-
-			if (Dependent.class.equals(beanScope)) {
-				configurator.add(ServiceInstance.Literal.of(ServiceScope.PROTOTYPE));
-			}
-		}
-		return of(configurator);
-	}
-
-	void afterDeploymentValidation(@Observes AfterDeploymentValidation adv) {
-		if (applications.size() > 1) {
-			adv.addDeploymentProblem(
-				new DeploymentException(
-					"More than one javax.ws.rs.core.Application annotated types were found in the CDI bundle."));
-		}
-	}
+    void afterDeploymentValidation(@Observes AfterDeploymentValidation adv) {
+        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."));
+        }
+    }
 
 }
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..6ecdf2b
--- /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 6c22b38..0000000
--- a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebFilterProcessor.java
+++ /dev/null
@@ -1,98 +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.BeanManager;
-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.MergeServiceTypes;
-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;
-import org.osgi.service.cdi.annotations.Service;
-
-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, BeanManager beanManager) {
-		if (pat.getAnnotatedType().isAnnotationPresent(Service.class)) {
-			return;
-		}
-
-		beanManager.fireEvent(new MergeServiceTypes<>(pat, Filter.class));
-		final AnnotatedTypeConfigurator<X> configurator = pat.configureAnnotatedType();
-		final AnnotatedType<X> 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()));
-		}
-	}
-
-}
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 55af105..0000000
--- a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebListenerProcessor.java
+++ /dev/null
@@ -1,94 +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.stream.Stream;
-
-import javax.enterprise.inject.spi.AnnotatedType;
-import javax.enterprise.inject.spi.BeanManager;
-import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
-import javax.servlet.ServletContextAttributeListener;
-import javax.servlet.ServletContextListener;
-import javax.servlet.ServletRequestAttributeListener;
-import javax.servlet.ServletRequestListener;
-import javax.servlet.annotation.WebListener;
-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.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;
-import org.osgi.service.cdi.annotations.Service;
-
-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, BeanManager beanManager) {
-		if (pat.getAnnotatedType().isAnnotationPresent(Service.class)) {
-			return;
-		}
-
-		final AnnotatedType<X> annotatedType = pat.getAnnotatedType();
-		final Class<X> 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(new MergeServiceTypes<>(pat, serviceTypes));
-
-		AnnotatedTypeConfigurator<X> 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()));
-		}
-	}
-
-}
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 9737085..0000000
--- a/cdi-extension-servlet-common/src/main/java/org/apache/aries/cdi/extension/servlet/common/WebServletProcessor.java
+++ /dev/null
@@ -1,107 +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.BeanManager;
-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.MergeServiceTypes;
-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;
-import org.osgi.service.cdi.annotations.Service;
-
-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, BeanManager beanManager) {
-		if (pat.getAnnotatedType().isAnnotationPresent(Service.class)) {
-			return;
-		}
-
-		beanManager.fireEvent(new MergeServiceTypes<>(pat, Servlet.class));
-
-		final AnnotatedTypeConfigurator<X> configurator = pat.configureAnnotatedType();
-		final AnnotatedType<X> 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 ???
-	}
-
-}
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 931cb77..e730189 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,165 +27,126 @@
 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 volatile ServletContext delegateContext;
-	volatile Configuration configuration;
+    private final BundleContext bundleContext;
+    private final ServletContext proxyContext;
+    private final ServletContextEvent startEvent;
+    private volatile ServletContext delegateContext;
 
-	public OWBServletExtension(Bundle bundle) {
-		super(new MockServletContext());
+    protected OWBServletExtension() { // proxy
+        bundleContext = null;
+        proxyContext = null;
+        startEvent = null;
+    }
 
-		this.bundleContext = bundle.getBundleContext();
+    public OWBServletExtension(Bundle bundle) {
+        this.startEvent = new ServletContextEvent(new MockServletContext()) {
+            @Override
+            public ServletContext getServletContext() {
+                return proxyContext;
+            }
+        };
 
-		// ensure we can switch the impl and keep ServletContextBean working with an updated context
-		this.proxyContext = ServletContext.class.cast(Proxy.newProxyInstance(ServletContext.class.getClassLoader(),
-				new Class<?>[]{ServletContext.class},
-				(proxy, method, args) -> {
-					try {
-						return method.invoke(ofNullable(delegateContext).orElseGet(OWBServletExtension.super::getServletContext), args);
-					}
-					catch (final InvocationTargetException ite) {
-						throw ite.getTargetException();
-					}
-				}));
-	}
+        this.bundleContext = bundle.getBundleContext();
 
-	public void setDelegate(final ServletContext delegateContext) {
-		this.delegateContext = delegateContext;
-	}
+        // ensure we can switch the impl and keep ServletContextBean working with an updated context
+        this.proxyContext = ServletContext.class.cast(Proxy.newProxyInstance(ServletContext.class.getClassLoader(),
+                new Class<?>[]{ServletContext.class},
+                (proxy, method, args) -> {
+                    try {
+                        return method.invoke(ofNullable(delegateContext).orElseGet(startEvent::getServletContext), args);
+                    } catch (final InvocationTargetException ite) {
+                        throw ite.getTargetException();
+                    }
+                }));
+    }
 
-	public ServletContext getOriginal() {
-		return super.getServletContext();
-	}
+    public void setDelegate(final ServletContext delegateContext) {
+        this.delegateContext = delegateContext;
+    }
+
+    void afterDeploymentValidation(
+            @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");
+        properties.put(SERVICE_VENDOR, "Apache Software Foundation");
+        properties.put(HTTP_WHITEBOARD_CONTEXT_SELECT, configuration.get(HTTP_WHITEBOARD_CONTEXT_SELECT));
+        properties.put(HTTP_WHITEBOARD_LISTENER, Boolean.TRUE.toString());
+        properties.put(SERVICE_RANKING, Integer.MAX_VALUE - 100);
+
+        _listenerRegistration = bundleContext.registerService(
+                LISTENER_CLASSES, new CdiListener(WebBeansContext.currentInstance()), properties);
+    }
+
+    private static final String[] LISTENER_CLASSES = new String[]{
+            ServletContextListener.class.getName(),
+            ServletRequestListener.class.getName(),
+            HttpSessionListener.class.getName()
+    };
 
 	@Override
-	public ServletContext getServletContext() {
-		return proxyContext;
+	public Object getStartObject() {
+		return startEvent;
 	}
 
-	void setConfiguration(@Observes Configuration configuration) {
-		this.configuration = configuration;
-	}
-
-	<X> void webFilter(@Observes @WithAnnotations(WebFilter.class) ProcessAnnotatedType<X> pat,
-					   BeanManager beanManager) {
-		new WebFilterProcessor().process(configuration, pat, beanManager);
-	}
-
-	<X> void webListener(@Observes @WithAnnotations(WebListener.class) ProcessAnnotatedType<X> pat,
-						 BeanManager beanManager) {
-		new WebListenerProcessor().process(configuration, pat, beanManager);
-	}
-
-	<X> void webServlet(@Observes @WithAnnotations(WebServlet.class) ProcessAnnotatedType<X> pat,
-						BeanManager beanManager) {
-		new WebServletProcessor().process(configuration, pat, beanManager);
-	}
-
-	void afterDeploymentValidation(
-		@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");
-		properties.put(SERVICE_VENDOR, "Apache Software Foundation");
-		properties.put(HTTP_WHITEBOARD_CONTEXT_SELECT, configuration.get(HTTP_WHITEBOARD_CONTEXT_SELECT));
-		properties.put(HTTP_WHITEBOARD_LISTENER, Boolean.TRUE.toString());
-		properties.put(SERVICE_RANKING, Integer.MAX_VALUE - 100);
-
-		_listenerRegistration = bundleContext.registerService(
-			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 volatile ServiceRegistration<?> _listenerRegistration;
-	private final AtomicBoolean destroyed = new AtomicBoolean(false);
-
 	private class CdiListener extends org.apache.webbeans.servlet.WebBeansConfigurationListener {
-		private final WebBeansContext webBeansContext;
+        private final WebBeansContext webBeansContext;
 
-		private CdiListener(final WebBeansContext webBeansContext) {
-			this.webBeansContext = webBeansContext;
-		}
+        private CdiListener(final WebBeansContext webBeansContext) {
+            this.webBeansContext = webBeansContext;
+        }
 
-		@Override
-		public void contextInitialized(ServletContextEvent event) {
-			ServletContext realSC = event.getServletContext();
+        @Override
+        public void contextInitialized(ServletContextEvent event) {
+            ServletContext realSC = event.getServletContext();
 
-			// update the sce to have the real one in CDI
-			setDelegate(realSC);
+            // update the sce to have the real one in CDI
+            setDelegate(realSC);
 
-			// propagate attributes from the temporary sc
-			list(getOriginal().getAttributeNames()).forEach(
-				attr -> realSC.setAttribute(attr, getOriginal().getAttribute(attr)));
+            // propagate attributes from the temporary sc
+            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);
+            realSC.setAttribute(BundleContext.class.getName(), bundleContext);
+            realSC.setAttribute(WebBeansContext.class.getName(), webBeansContext);
 
-			// already started in the activator so let's skip it, just ensure it is skipped if re-called
-			event.getServletContext().setAttribute(getClass().getName(), true);
-			if (lifeCycle == null) {
-				lifeCycle = webBeansContext.getService(ContainerLifecycle.class);
-			}
-		}
+            // already started in the activator so let's skip it, just ensure it is skipped if re-called
+            event.getServletContext().setAttribute(getClass().getName(), true);
+            if (lifeCycle == null) {
+                lifeCycle = webBeansContext.getService(ContainerLifecycle.class);
+            }
+        }
 
-		@Override
-		public void contextDestroyed(ServletContextEvent sce) {
-			try {
-				super.contextDestroyed(sce);
-			}
-			finally {
-				destroyed.set(true);
-			}
-		}
-	}
+        @Override
+        public void contextDestroyed(ServletContextEvent sce) {
+            try {
+                super.contextDestroyed(sce);
+            } 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 db86224..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,58 +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,
-					   BeanManager beanManager) {
-		new WebFilterProcessor().process(configuration, pat, beanManager);
-	}
-
-	<X> void webListener(@Observes @WithAnnotations(WebListener.class) ProcessAnnotatedType<X> pat,
-						 BeanManager beanManager) {
-		new WebListenerProcessor().process(configuration, pat, beanManager);
-	}
-
-	<X> void webServlet(@Observes @WithAnnotations(WebServlet.class) ProcessAnnotatedType<X> pat,
-						BeanManager beanManager) {
-		new WebServletProcessor().process(configuration, pat, beanManager);
-	}
-
 	void afterDeploymentValidation(
 		@Observes @Priority(LIBRARY_AFTER + 800)
 		AfterDeploymentValidation adv, BeanManager beanManager) {
@@ -114,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/FiltersOn.java b/cdi-extension-spi/src/main/java/org/apache/aries/cdi/extension/spi/adapt/FiltersOn.java
new file mode 100644
index 0000000..573dbd4
--- /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
index e163269..a96e12e 100644
--- 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
@@ -17,11 +17,16 @@
 
 import javax.enterprise.inject.spi.ProcessAnnotatedType;
 
-public class MergeServiceTypes<T> {
+/**
+ * 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<T> processAnnotatedType;
+    private final ProcessAnnotatedType<?> processAnnotatedType;
 
-    public MergeServiceTypes(final ProcessAnnotatedType<T> processAnnotatedType,
+    private MergeServiceTypes(final ProcessAnnotatedType<?> processAnnotatedType,
                              final Class<?>... types) {
         this.types = types;
         this.processAnnotatedType = processAnnotatedType;
@@ -31,7 +36,7 @@
         return types;
     }
 
-    public ProcessAnnotatedType<T> getProcessAnnotatedType() {
+    public ProcessAnnotatedType<?> getProcessAnnotatedType() {
         return processAnnotatedType;
     }
 
@@ -39,4 +44,36 @@
     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..4303f74
--- /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..f352716
--- /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/package-info.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/spi/StartObjectSupplier.java
similarity index 64%
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/StartObjectSupplier.java
index 5e523d8..a4590f3 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/StartObjectSupplier.java
@@ -11,10 +11,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.aries.cdi.owb.spi;
 
-@org.osgi.annotation.bundle.Capability(
-	attribute = "objectClass:List<String>=org.apache.aries.cdi.spi.CDIContainerInitializer",
-	namespace = org.osgi.namespace.service.ServiceNamespace.SERVICE_NAMESPACE
-)
-@org.osgi.service.cdi.annotations.RequireCDIImplementation
-package org.apache.aries.cdi.owb;
+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