You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ro...@apache.org on 2019/11/25 18:43:28 UTC

[aries-cdi] 09/27: add OpenWebBeans CDI container that uses the Aries CDI SPI

This is an automated email from the ASF dual-hosted git repository.

rotty3000 pushed a commit to branch rotty3000/cdi-spi
in repository https://gitbox.apache.org/repos/asf/aries-cdi.git

commit fdc50ee6b63330e26d6c9e13b8aefbc163ee7225
Author: Raymond Augé <ro...@apache.org>
AuthorDate: Fri Nov 22 12:42:53 2019 -0500

    add OpenWebBeans CDI container that uses the Aries CDI SPI
    
    Signed-off-by: Raymond Augé <ro...@apache.org>
    Signed-off-by: Romain Manni-Bucau <rm...@gmail.com>
---
 cdi-bom/pom.xml                                    |   6 +
 .../{executable.bndrun => owb-executable.bndrun}   |  30 +-
 cdi-executable/pom.xml                             |   8 +-
 cdi-owb/pom.xml                                    | 149 +++++++++
 .../java/org/apache/aries/cdi/owb/Activator.java   |  74 +++++
 .../apache/aries/cdi/owb/CdiScannerService.java    |  62 ++++
 .../aries/cdi/owb/OSGiDefiningClassService.java    |  72 ++++
 .../aries/cdi/owb/OWBSeContainerInitializer.java   | 357 ++++++++++++++++++++
 .../cdi/owb/OWBSeContainerInitializerFactory.java  |  44 +++
 .../cdi/owb/OsgiApplicationBoundaryService.java    |  44 +++
 .../org/apache/aries/cdi/owb/package-info.java     |  23 ++
 .../aries/cdi/owb/web/UpdatableServletContext.java |  67 ++++
 .../org/apache/aries/cdi/owb/web/WebExtension.java | 367 +++++++++++++++++++++
 .../aries/cdi/owb/web/WebExtensionFactory.java     |  37 +++
 .../org/apache/aries/cdi/owb/web/package-info.java |  45 +++
 pom.xml                                            |   4 +-
 16 files changed, 1369 insertions(+), 20 deletions(-)

diff --git a/cdi-bom/pom.xml b/cdi-bom/pom.xml
index 794e2d1..d3b97c4 100644
--- a/cdi-bom/pom.xml
+++ b/cdi-bom/pom.xml
@@ -82,6 +82,12 @@
 				<scope>compile</scope>
 			</dependency>
 			<dependency>
+				<groupId>org.apache.aries.cdi</groupId>
+				<artifactId>org.apache.aries.cdi.owb</artifactId>
+				<version>${project.version}</version>
+				<scope>runtime</scope>
+			</dependency>
+			<dependency>
 				<groupId>org.apache.aries.spifly</groupId>
 				<artifactId>org.apache.aries.spifly.dynamic.framework.extension</artifactId>
 				<version>1.2</version>
diff --git a/cdi-executable/executable.bndrun b/cdi-executable/owb-executable.bndrun
similarity index 73%
rename from cdi-executable/executable.bndrun
rename to cdi-executable/owb-executable.bndrun
index 02b26d4..14a9500 100644
--- a/cdi-executable/executable.bndrun
+++ b/cdi-executable/owb-executable.bndrun
@@ -25,10 +25,7 @@
 
 -resolve.effective: resolve, active
 -runrequires: \
-	osgi.identity;filter:='(osgi.identity=javax.ejb-api)',\
-	osgi.identity;filter:='(osgi.identity=javax.transaction-api)',\
-	osgi.identity;filter:='(osgi.identity=org.apache.aries.cdi.extension.http)',\
-	osgi.identity;filter:='(osgi.identity=org.apache.aries.cdi.extra)',\
+	osgi.identity;filter:='(osgi.identity=org.apache.aries.cdi.owb)',\
 	osgi.identity;filter:='(osgi.identity=org.apache.felix.gogo.command)'
 
 -runpath: \
@@ -38,32 +35,35 @@
 	slf4j.api
 
 -runsystempackages: \
-	org.slf4j;version=1.7.25,\
-	org.slf4j.helpers;version=1.7.25,\
-	org.slf4j.spi;version=1.7.25,\
+	org.slf4j;version=1.7.28,\
+	org.slf4j.event;version=1.7.28,\
+	org.slf4j.helpers;version=1.7.28,\
+	org.slf4j.spi;version=1.7.28,\
 	sun.misc
 
 -runbundles: \
-	javax.ejb-api;version='[3.2.0,3.2.1)',\
-	javax.transaction-api;version='[1.2.0,1.2.1)',\
-	jboss-classfilewriter;version='[1.2.3,1.2.4)',\
+	javax.servlet.jsp-api;version='[2.3.3,2.3.4)',\
+	openwebbeans-impl;version='[2.0.13,2.0.14)',\
+	openwebbeans-spi;version='[2.0.13,2.0.14)',\
+	openwebbeans-web;version='[2.0.13,2.0.14)',\
 	org.apache.aries.cdi.extender;version='[1.0.3,1.0.4)',\
-	org.apache.aries.cdi.extension.http;version='[1.0.3,1.0.4)',\
 	org.apache.aries.cdi.extra;version='[1.0.3,1.0.4)',\
+	org.apache.aries.cdi.owb;version='[1.0.3,1.0.4)',\
+	org.apache.aries.cdi.spi;version='[1.0.3,1.0.4)',\
 	org.apache.aries.spifly.dynamic.framework.extension;version='[1.2.0,1.2.1)',\
 	org.apache.felix.configadmin;version='[1.9.10,1.9.11)',\
 	org.apache.felix.gogo.command;version='[1.1.0,1.1.1)',\
 	org.apache.felix.gogo.runtime;version='[1.1.2,1.1.3)',\
 	org.apache.felix.gogo.shell;version='[1.1.2,1.1.3)',\
-	org.apache.felix.http.jetty;version='[4.0.6,4.0.7)',\
 	org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
 	org.apache.geronimo.specs.geronimo-annotation_1.3_spec;version='[1.1.0,1.1.1)',\
 	org.apache.geronimo.specs.geronimo-atinject_1.0_spec;version='[1.1.0,1.1.1)',\
 	org.apache.geronimo.specs.geronimo-el_2.2_spec;version='[1.1.0,1.1.1)',\
 	org.apache.geronimo.specs.geronimo-interceptor_1.2_spec;version='[1.1.0,1.1.1)',\
 	org.apache.geronimo.specs.geronimo-jcdi_2.0_spec;version='[1.1.0,1.1.1)',\
-	org.jboss.logging.jboss-logging;version='[3.3.2,3.3.3)',\
-	org.jboss.weld.osgi-bundle;version='[3.0.5,3.0.6)',\
+	org.apache.xbean.asm7-shaded;version='[4.13.0,4.13.1)',\
+	org.apache.xbean.bundleutils;version='[4.15.0,4.15.1)',\
+	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)'
diff --git a/cdi-executable/pom.xml b/cdi-executable/pom.xml
index df95188..0cca58d 100644
--- a/cdi-executable/pom.xml
+++ b/cdi-executable/pom.xml
@@ -79,7 +79,7 @@
 				<artifactId>bnd-resolver-maven-plugin</artifactId>
 				<configuration>
 					<bndruns>
-						<bndrun>executable.bndrun</bndrun>
+						<bndrun>owb-executable.bndrun</bndrun>
 					</bndruns>
 					<includeDependencyManagement>true</includeDependencyManagement>
 				</configuration>
@@ -89,7 +89,7 @@
 				<artifactId>bnd-export-maven-plugin</artifactId>
 				<configuration>
 					<bndruns>
-						<bndrun>executable.bndrun</bndrun>
+						<bndrun>owb-executable.bndrun</bndrun>
 					</bndruns>
 					<includeDependencyManagement>true</includeDependencyManagement>
 				</configuration>
@@ -99,9 +99,9 @@
 				<artifactId>bnd-run-maven-plugin</artifactId>
 				<executions>
 					<execution>
-						<id>executable</id>
+						<id>owb-executable</id>
 						<configuration>
-							<bndrun>executable.bndrun</bndrun>
+							<bndrun>owb-executable.bndrun</bndrun>
 						</configuration>
 					</execution>
 				</executions>
diff --git a/cdi-owb/pom.xml b/cdi-owb/pom.xml
new file mode 100644
index 0000000..d700abe
--- /dev/null
+++ b/cdi-owb/pom.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.aries.cdi</groupId>
+		<artifactId>org.apache.aries.cdi</artifactId>
+		<version>1.0.3-SNAPSHOT</version>
+		<relativePath>..</relativePath>
+	</parent>
+
+	<artifactId>org.apache.aries.cdi.owb</artifactId>
+	<name>Apache Aries CDI - Container using Apache OpenWebBeans</name>
+	<description>Apache Aries CDI - Container using Apache OpenWebBeans</description>
+
+	<licenses>
+		<license>
+			<name>ASL 2.0</name>
+			<url>https://www.apache.org/licenses/LICENSE-2.0</url>
+		</license>
+	</licenses>
+
+	<scm>
+		<connection>scm:git:git@github.com:apache/aries-cdi.git</connection>
+		<developerConnection>scm:git:git@github.com:apache/aries-cdi.git</developerConnection>
+		<tag>HEAD</tag>
+		<url>https://github.com/apache/aries-cdi</url>
+	</scm>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>biz.aQute.bnd</groupId>
+				<artifactId>bnd-maven-plugin</artifactId>
+				<configuration>
+					<bnd><![CDATA[
+						-cdiannotations:
+						-noclassforname: true
+						#Import-Package: \
+						#	org.apache.webbeans.servlet;resolution:=optional,\
+						#	org.apache.webbeans.web.*;resolution:=optional,\
+						#	javax.servlet.*;resolution:=optional,\
+						#	*
+					]]></bnd>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.aries.cdi</groupId>
+			<artifactId>org.apache.aries.cdi.extra</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.aries.cdi</groupId>
+			<artifactId>org.apache.aries.cdi.spi</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.geronimo.specs</groupId>
+			<artifactId>geronimo-annotation_1.3_spec</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.geronimo.specs</groupId>
+			<artifactId>geronimo-atinject_1.0_spec</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.geronimo.specs</groupId>
+			<artifactId>geronimo-interceptor_1.2_spec</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.geronimo.specs</groupId>
+			<artifactId>geronimo-jcdi_2.0_spec</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.openwebbeans</groupId>
+			<artifactId>openwebbeans-impl</artifactId>
+			<version>${owb.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.openwebbeans</groupId>
+			<artifactId>openwebbeans-web</artifactId>
+			<version>${owb.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.xbean</groupId>
+			<artifactId>xbean-bundleutils</artifactId>
+			<version>4.15</version>
+			<exclusions>
+				<exclusion>
+					<groupId>org.slf4j</groupId>
+					<artifactId>slf4j-api</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.apache.felix.http.servlet-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.namespace.extender</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.namespace.implementation</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.namespace.service</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.service.cdi</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.service.http.whiteboard</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>osgi.annotation</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>osgi.core</artifactId>
+		</dependency>
+	</dependencies>
+
+</project>
\ No newline at end of file
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/Activator.java
new file mode 100644
index 0000000..8a17c96
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/Activator.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.aries.cdi.owb;
+
+import static org.osgi.framework.Constants.BUNDLE_ACTIVATOR;
+import static org.osgi.framework.Constants.SERVICE_DESCRIPTION;
+import static org.osgi.framework.Constants.SERVICE_VENDOR;
+import static org.osgi.service.cdi.CDIConstants.CDI_EXTENSION_PROPERTY;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.enterprise.inject.se.SeContainerInitializer;
+import javax.enterprise.inject.spi.Extension;
+
+import org.osgi.annotation.bundle.Header;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+@Header(
+	name = BUNDLE_ACTIVATOR,
+	value = "${@class}"
+)
+public class Activator implements BundleActivator {
+
+	public static final boolean webEnabled = true;
+
+	@Override
+	public void start(BundleContext bundleContext) throws Exception {
+		System.setProperty("openwebbeans.web.sci.active", "false"); // we handle it ourself, disable this jetty feature
+		Dictionary<String, Object> properties = new Hashtable<>();
+		properties.put(SERVICE_DESCRIPTION, "Aries CDI - OpenWebBeans SeContainerInitializer Factory");
+		properties.put(SERVICE_VENDOR, "Apache Software Foundation");
+		properties.put("aries.cdi.spi", "OpenWebBeans");
+
+		_seContainerInitializer = bundleContext.registerService(
+			SeContainerInitializer.class, new OWBSeContainerInitializerFactory(bundleContext), properties);
+
+		if (webEnabled) {
+			properties = new Hashtable<>();
+			properties.put(CDI_EXTENSION_PROPERTY, "aries.cdi.http");
+			properties.put(SERVICE_DESCRIPTION, "Aries CDI - OpenWebBeans Web Extension Factory");
+			properties.put(SERVICE_VENDOR, "Apache Software Foundation");
+
+			_webExtension = bundleContext.registerService(
+				Extension.class, new org.apache.aries.cdi.owb.web.WebExtensionFactory(), properties);
+		}
+	}
+
+	@Override
+	public void stop(BundleContext context) throws Exception {
+		_seContainerInitializer.unregister();
+		if (_webExtension != null) {
+			_webExtension.unregister();
+		}
+	}
+
+	private ServiceRegistration<SeContainerInitializer> _seContainerInitializer;
+	private ServiceRegistration<Extension> _webExtension;
+
+}
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/CdiScannerService.java
new file mode 100644
index 0000000..b0dcb30
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/CdiScannerService.java
@@ -0,0 +1,62 @@
+package org.apache.aries.cdi.owb;
+
+import static java.util.Collections.*;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.webbeans.corespi.se.DefaultBDABeansXmlScanner;
+import org.apache.webbeans.spi.BDABeansXmlScanner;
+import org.apache.webbeans.spi.ScannerService;
+
+// todo: bda support
+@SuppressWarnings("deprecation")
+public class CdiScannerService implements ScannerService {
+	private final Set<Class<?>> classes;
+	private final Set<URL> beansXml;
+	private BDABeansXmlScanner bdaBeansXmlScanner = new DefaultBDABeansXmlScanner();
+
+	public CdiScannerService(final Set<Class<?>> beanClassNames,
+							final Collection<URL> beansXml) {
+		this.classes = beanClassNames;
+		this.beansXml = beansXml == null ? emptySet() : new HashSet<>(beansXml);
+	}
+
+	@Override
+	public void init(final Object object) {
+		// no-op
+	}
+
+	@Override
+	public void scan() {
+		// we already scanned
+	}
+
+	@Override
+	public void release() {
+		// no-op
+	}
+
+	@Override
+	public Set<URL> getBeanXmls() {
+		return beansXml;
+	}
+
+	@Override
+	public Set<Class<?>> getBeanClasses() {
+		return classes;
+	}
+
+	@Override
+	public boolean isBDABeansXmlScanningEnabled() {
+		return false;
+	}
+
+	@Override
+	public BDABeansXmlScanner getBDABeansXmlScanner() {
+		return bdaBeansXmlScanner;
+	}
+
+}
\ No newline at end of file
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/OSGiDefiningClassService.java
new file mode 100644
index 0000000..62c5e71
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OSGiDefiningClassService.java
@@ -0,0 +1,72 @@
+/**
+ * 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.owb;
+
+import java.lang.reflect.Modifier;
+
+import org.apache.aries.cdi.spi.loader.SpiLoader;
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.proxy.Unsafe;
+import org.apache.webbeans.spi.DefiningClassService;
+
+public class OSGiDefiningClassService implements DefiningClassService {
+	private final Unsafe unsafe;
+	private final ClassLoaders classloaders;
+
+	public OSGiDefiningClassService(final WebBeansContext context) {
+		this.unsafe = new Unsafe();
+		this.classloaders = context.getService(ClassLoaders.class);
+	}
+
+	@Override
+	public ClassLoader getProxyClassLoader(final Class<?> aClass) {
+		return classloaders.loader;
+	}
+
+	/**
+	 * We prefer to register the proxy in the dedicated cdi classloader but due to classloader rules it is not always possible.
+	 * In such cases we try to use unsafe.
+	 *
+	 * @param name proxy name.
+	 * @param bytes proxy bytecode.
+	 * @param proxied proxied class.
+	 * @param <T> proxied type.
+	 * @return the proxy class instance.
+	 */
+	@Override
+	public <T> Class<T> defineAndLoad(final String name, final byte[] bytes, final Class<T> proxied) {
+		if (requiresUnsafe(proxied)) { // todo: today we don't really support that
+			final ClassLoader classLoader = proxied.getClassLoader();
+			if (classLoader != classloaders.bundleLoader) {
+				// todo: log a warning?
+			}
+			return unsafe.defineAndLoadClass(classLoader, name, bytes);
+		}
+		return (Class<T>) classloaders.loader.getOrRegister(name, bytes, proxied.getPackage(), proxied.getProtectionDomain());
+	}
+
+	private boolean requiresUnsafe(final Class<?> aClass) {
+		return !Modifier.isPublic(aClass.getModifiers());
+	}
+
+	public static class ClassLoaders {
+		private final ClassLoader bundleLoader;
+		private final SpiLoader loader;
+
+		public ClassLoaders(final ClassLoader bundleLoader, final SpiLoader loader) {
+			this.bundleLoader = bundleLoader;
+			this.loader = loader;
+		}
+	}
+}
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBSeContainerInitializer.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBSeContainerInitializer.java
new file mode 100644
index 0000000..f37abdb
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBSeContainerInitializer.java
@@ -0,0 +1,357 @@
+package org.apache.aries.cdi.owb;
+
+import static java.util.Collections.list;
+import static java.util.Objects.requireNonNull;
+import static org.apache.aries.cdi.spi.Keys.BEANS_XML_PROPERTY;
+import static org.apache.aries.cdi.spi.Keys.BUNDLECONTEXT_PROPERTY;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.se.SeContainer;
+import javax.enterprise.inject.se.SeContainerInitializer;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.util.TypeLiteral;
+
+import org.apache.aries.cdi.spi.loader.SpiLoader;
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.config.WebBeansFinder;
+import org.apache.webbeans.corespi.DefaultSingletonService;
+import org.apache.webbeans.portable.events.ExtensionLoader;
+import org.apache.webbeans.spi.ApplicationBoundaryService;
+import org.apache.webbeans.spi.ContainerLifecycle;
+import org.apache.webbeans.spi.ContextsService;
+import org.apache.webbeans.spi.ConversationService;
+import org.apache.webbeans.spi.DefiningClassService;
+import org.apache.webbeans.spi.ScannerService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleWire;
+import org.osgi.framework.wiring.BundleWiring;
+
+public class OWBSeContainerInitializer extends SeContainerInitializer {
+
+	public OWBSeContainerInitializer(BundleContext bundleContext) {
+		owbBundleContext = bundleContext;
+	}
+
+	@Override
+	public SeContainerInitializer addBeanClasses(Class<?>... classes) {
+		beanClasses.addAll(Arrays.asList(classes));
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer addPackages(Class<?>... packageClasses) {
+		// TODO Auto-generated method stub
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer addPackages(boolean scanRecursively, Class<?>... packageClasses) {
+		// TODO Auto-generated method stub
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer addPackages(Package... packages) {
+		// TODO Auto-generated method stub
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer addPackages(boolean scanRecursively, Package... packages) {
+		// TODO Auto-generated method stub
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer addExtensions(Extension... extensions) {
+		this.extensions.addAll(Arrays.asList(extensions));
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer addExtensions(Class<? extends Extension>... extensions) {
+		this.extensionClasses.addAll(Arrays.asList(extensions));
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer enableInterceptors(Class<?>... interceptorClasses) {
+		// TODO Auto-generated method stub
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer enableDecorators(Class<?>... decoratorClasses) {
+		// TODO Auto-generated method stub
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer selectAlternatives(Class<?>... alternativeClasses) {
+		// TODO Auto-generated method stub
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer selectAlternativeStereotypes(
+		Class<? extends Annotation>... alternativeStereotypeClasses) {
+
+		// TODO Auto-generated method stub
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer addProperty(String key, Object value) {
+		properties.putIfAbsent(key, value);
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer setProperties(Map<String, Object> properties) {
+		properties.putAll(properties);
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer disableDiscovery() {
+		// TODO Auto-generated method stub
+		return this;
+	}
+
+	@Override
+	public SeContainerInitializer setClassLoader(ClassLoader classLoader) {
+		this.classLoader = (SpiLoader)classLoader;
+		return this;
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	public SeContainer initialize() {
+		requireNonNull(classLoader).handleResources(
+			s -> (s != null) && s.startsWith("META-INF/openwebbeans/"),
+			this::getResources
+		).findClass(
+			s -> (s != null) && (s.startsWith("org.apache.webbeans.") || s.startsWith("sun.misc.")),
+			this::loadClass);
+
+		classLoader.getBundles().add(owbBundleContext.getBundle());
+
+		BundleWiring bundleWiring = owbBundleContext.getBundle().adapt(BundleWiring.class);
+		List<BundleWire> requiredWires = bundleWiring.getRequiredWires(PackageNamespace.PACKAGE_NAMESPACE);
+
+		for (BundleWire bundleWire : requiredWires) {
+			BundleCapability capability = bundleWire.getCapability();
+			Map<String, Object> attributes = capability.getAttributes();
+			String packageName = (String)attributes.get(PackageNamespace.PACKAGE_NAMESPACE);
+			if (!packageName.startsWith("org.apache.webbeans.")) {
+				continue;
+			}
+
+			Bundle wireBundle = bundleWire.getProvider().getBundle();
+			if (!classLoader.getBundles().contains(wireBundle)) {
+				classLoader.getBundles().add(wireBundle);
+			}
+		}
+
+		Thread currentThread = Thread.currentThread();
+		ClassLoader current = currentThread.getContextClassLoader();
+
+		try {
+			currentThread.setContextClassLoader(classLoader);
+			clientBundleContext = requireNonNull(BundleContext.class.cast(properties.get(BUNDLECONTEXT_PROPERTY)));
+			startObject = clientBundleContext;
+
+			final Map<Class<?>, Object> services = new HashMap<>();
+			properties.setProperty(
+				DefiningClassService.class.getName(),
+				OSGiDefiningClassService.class.getName());
+
+			services.put(
+				OSGiDefiningClassService.ClassLoaders.class,
+				new OSGiDefiningClassService.ClassLoaders(current, classLoader));
+			services.put(
+				ApplicationBoundaryService.class,
+				new OsgiApplicationBoundaryService(current, classLoader));
+			services.put(
+				ScannerService.class,
+				new CdiScannerService(beanClasses, Collection.class.cast(properties.get(BEANS_XML_PROPERTY))));
+			services.put(BundleContext.class, clientBundleContext);
+
+			if (Activator.webEnabled) {
+				// Web mode - minimal set, see META-INF/openwebbeans/openwebbeans.properties in openwebbeans-web for details
+				// todo: enable to not use web?
+				properties.setProperty(
+					ContainerLifecycle.class.getName(),
+					org.apache.webbeans.web.lifecycle.WebContainerLifecycle.class.getName());
+				properties.setProperty(
+					ContextsService.class.getName(),
+					org.apache.webbeans.web.context.WebContextsService.class.getName());
+				properties.setProperty(
+					ConversationService.class.getName(),
+					org.apache.webbeans.web.context.WebConversationService.class.getName());
+
+				startObject = new org.apache.aries.cdi.owb.web.UpdatableServletContext(bootstrap, clientBundleContext);
+				services.put(org.apache.aries.cdi.owb.web.UpdatableServletContext.class, startObject);
+			}
+
+			Optional.ofNullable(clientBundleContext.getBundle().getHeaders()).ifPresent(
+				headers -> list(headers.elements()).stream()
+					.filter(it -> it.startsWith("org.apache.openwebbeans."))
+					.forEach(key -> properties.setProperty(key, headers.get(key))
+				)
+			);
+
+			bootstrap = new WebBeansContext(services, properties) {
+				private final ExtensionLoader overridenExtensionLoader = new ExtensionLoader(this) {
+					@Override
+					public void loadExtensionServices() {
+						extensions.removeIf(ext -> {addExtension(ext); return true;});
+					}
+				};
+
+				@Override
+				public ExtensionLoader getExtensionLoader() {
+					return overridenExtensionLoader;
+				}
+			};
+
+			final DefaultSingletonService singletonService = getSingletonService();
+			singletonService.register(classLoader, bootstrap);
+			final ContainerLifecycle lifecycle = bootstrap.getService(ContainerLifecycle.class);
+			lifecycle.startApplication(startObject);
+
+			return new OWBSeContainer();
+		}
+		finally {
+			currentThread.setContextClassLoader(current);
+		}
+	}
+
+	protected Enumeration<URL> getResources(String name) {
+		try {
+			return WebBeansContext.class.getClassLoader().getResources(name);
+		} catch (IOException e) {
+			throwsUnchecked(e);
+			return null; // unreachable
+		}
+	}
+
+	protected Class<?> loadClass(String name) {
+		try {
+			return WebBeansContext.class.getClassLoader().loadClass(name);
+		} catch (ClassNotFoundException e) {
+			throwsUnchecked(e);
+			return null; // unreachable
+		}
+	}
+
+	protected DefaultSingletonService getSingletonService() {
+		return DefaultSingletonService.class.cast(WebBeansFinder.getSingletonService());
+	}
+
+	@SuppressWarnings("unchecked")
+	private static <E extends Throwable> void throwsUnchecked(Throwable throwable) throws E {
+		throw (E) throwable;
+	}
+
+	private volatile WebBeansContext bootstrap;
+	private volatile BundleContext clientBundleContext;
+	private volatile SpiLoader classLoader;
+	private final Set<Class<?>> beanClasses = new HashSet<>();
+	private final List<Extension> extensions = new ArrayList<>();
+	private final List<Class<? extends Extension>> extensionClasses = new ArrayList<>();
+	private final BundleContext owbBundleContext;
+	private final Properties properties = new Properties();
+	private Object startObject;
+
+	private class OWBSeContainer implements SeContainer {
+
+		private volatile boolean running = true;
+
+		@Override
+		public void close() {
+			running = false;
+			Thread currentThread = Thread.currentThread();
+			ClassLoader current = currentThread.getContextClassLoader();
+			try {
+				currentThread.setContextClassLoader(requireNonNull(classLoader));
+				bootstrap.getService(ContainerLifecycle.class).stopApplication(startObject);
+			}
+			finally {
+				currentThread.setContextClassLoader(current);
+			}
+		}
+
+		@Override
+		public Instance<Object> select(Annotation... qualifiers) {
+			return bootstrap.getBeanManagerImpl().createInstance().select(qualifiers);
+		}
+
+		@Override
+		public <U> Instance<U> select(Class<U> subtype, Annotation... qualifiers) {
+			return bootstrap.getBeanManagerImpl().createInstance().select(subtype, qualifiers);
+		}
+
+		@Override
+		public <U> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers) {
+			return bootstrap.getBeanManagerImpl().createInstance().select(subtype, qualifiers);
+		}
+
+		@Override
+		public boolean isUnsatisfied() {
+			return bootstrap.getBeanManagerImpl().createInstance().isUnsatisfied();
+		}
+
+		@Override
+		public boolean isAmbiguous() {
+			return bootstrap.getBeanManagerImpl().createInstance().isAmbiguous();
+		}
+
+		@Override
+		public void destroy(Object instance) {
+			bootstrap.getBeanManagerImpl().createInstance().destroy(instance);
+		}
+
+		@Override
+		public Iterator<Object> iterator() {
+			return bootstrap.getBeanManagerImpl().createInstance().iterator();
+		}
+
+		@Override
+		public boolean isRunning() {
+			return running;
+		}
+
+		@Override
+		public BeanManager getBeanManager() {
+			return bootstrap.getBeanManagerImpl();
+		}
+
+		@Override
+		public Object get() {
+			return bootstrap.getBeanManagerImpl().createInstance().get();
+		}
+
+	}
+
+}
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBSeContainerInitializerFactory.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBSeContainerInitializerFactory.java
new file mode 100644
index 0000000..87e1b7c
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OWBSeContainerInitializerFactory.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.aries.cdi.owb;
+
+import javax.enterprise.inject.se.SeContainerInitializer;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.PrototypeServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+public class OWBSeContainerInitializerFactory implements PrototypeServiceFactory<SeContainerInitializer> {
+
+	public OWBSeContainerInitializerFactory(BundleContext bundleContext) {
+		this.bundleContext = bundleContext;
+	}
+
+	@Override
+	public SeContainerInitializer getService(
+		Bundle bundle, ServiceRegistration<SeContainerInitializer> registration) {
+
+		return new OWBSeContainerInitializer(bundleContext);
+	}
+
+	@Override
+	public void ungetService(
+		Bundle bundle, ServiceRegistration<SeContainerInitializer> registration, SeContainerInitializer service) {
+	}
+
+	private final BundleContext bundleContext;
+
+}
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/OsgiApplicationBoundaryService.java
new file mode 100644
index 0000000..a9da88f
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/OsgiApplicationBoundaryService.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aries.cdi.owb;
+
+import org.apache.webbeans.spi.ApplicationBoundaryService;
+
+public class OsgiApplicationBoundaryService implements ApplicationBoundaryService {
+    private final ClassLoader bundleLoader;
+    private final ClassLoader loader;
+
+    public OsgiApplicationBoundaryService(final ClassLoader bundleLoader, final ClassLoader loader) {
+        this.bundleLoader = bundleLoader;
+        this.loader = loader;
+    }
+
+    @Override
+    public ClassLoader getApplicationClassLoader() {
+        return bundleLoader;
+    }
+
+    @Override
+    public ClassLoader getBoundaryClassLoader(final Class aClass) {
+        final ClassLoader classToProxyCl = aClass.getClassLoader();
+        if (classToProxyCl == null || classToProxyCl == loader) {
+            return loader;
+        }
+        if (classToProxyCl == bundleLoader) {
+            return classToProxyCl;
+        }
+        // todo: refine if needed
+        return classToProxyCl;
+    }
+}
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/package-info.java
new file mode 100644
index 0000000..063d4c7
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@org.osgi.annotation.bundle.Capability(
+	attribute = {
+		"objectClass:List<String>=javax.enterprise.inject.se.SeContainerInitializer",
+		"aries.cdi.spi=OpenWebBeans"
+	},
+	namespace = org.osgi.namespace.service.ServiceNamespace.SERVICE_NAMESPACE
+)
+@org.osgi.service.cdi.annotations.RequireCDIImplementation
+package org.apache.aries.cdi.owb;
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/UpdatableServletContext.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/UpdatableServletContext.java
new file mode 100644
index 0000000..a732a3e
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/UpdatableServletContext.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aries.cdi.owb.web;
+
+import static java.util.Optional.ofNullable;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.web.lifecycle.test.MockServletContext;
+import org.osgi.framework.BundleContext;
+
+@SuppressWarnings("serial")
+public class UpdatableServletContext extends ServletContextEvent {
+	private final WebBeansContext bootstrap;
+	private final BundleContext bundleContext;
+	private final ServletContext context;
+	private ServletContext delegate;
+
+	public UpdatableServletContext(WebBeansContext bootstrap, BundleContext bundleContext) {
+		super(new MockServletContext());
+		this.bootstrap = bootstrap;
+		this.bundleContext = bundleContext;
+
+		// ensure we can switch the impl and keep ServletContextBean working with an updated context
+		this.context = ServletContext.class.cast(Proxy.newProxyInstance(ServletContext.class.getClassLoader(),
+				new Class<?>[]{ServletContext.class},
+				(proxy, method, args) -> {
+					try {
+						return method.invoke(ofNullable(delegate).orElseGet(UpdatableServletContext.super::getServletContext), args);
+					}
+					catch (final InvocationTargetException ite) {
+						throw ite.getTargetException();
+					}
+				}));
+	}
+
+	public void setDelegate(final ServletContext delegate) {
+		this.delegate = delegate;
+		this.delegate.setAttribute(BundleContext.class.getName(), bundleContext);
+		this.delegate.setAttribute(WebBeansContext.class.getName(), bootstrap);
+	}
+
+	public ServletContext getOriginal() {
+		return super.getServletContext();
+	}
+
+	@Override
+	public ServletContext getServletContext() {
+		return context;
+	}
+}
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/WebExtension.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/WebExtension.java
new file mode 100644
index 0000000..d07a618
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/WebExtension.java
@@ -0,0 +1,367 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.aries.cdi.owb.web;
+
+import static java.util.Collections.list;
+import static javax.interceptor.Interceptor.Priority.LIBRARY_AFTER;
+import static org.osgi.framework.Constants.SERVICE_DESCRIPTION;
+import static org.osgi.framework.Constants.SERVICE_RANKING;
+import static org.osgi.framework.Constants.SERVICE_VENDOR;
+import static org.osgi.namespace.extender.ExtenderNamespace.EXTENDER_NAMESPACE;
+import static org.osgi.service.cdi.CDIConstants.CDI_CAPABILITY_NAME;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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.AnnotatedType;
+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.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+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.HttpSessionListener;
+
+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.webbeans.config.WebBeansContext;
+import org.apache.webbeans.spi.ContainerLifecycle;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleWire;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.service.cdi.annotations.Service;
+
+public class WebExtension implements Extension {
+
+	public WebExtension(Bundle bundle) {
+		_bundle = bundle;
+	}
+
+	<X> void processWebFilter(@Observes @WithAnnotations(WebFilter.class) ProcessAnnotatedType<X> pat) {
+		final AnnotatedType<X> annotatedType = pat.getAnnotatedType();
+
+		WebFilter webFilter = annotatedType.getAnnotation(WebFilter.class);
+
+		final Set<Annotation> annotationsToAdd = new HashSet<>();
+
+		if (!annotatedType.isAnnotationPresent(Service.class)) {
+			annotationsToAdd.add(Service.Literal.of(new Class[] {Filter.class}));
+		}
+
+		if(!annotatedType.isAnnotationPresent(HttpWhiteboardContextSelect.class)) {
+			annotationsToAdd.add(HttpWhiteboardContextSelect.Literal.of(getSelectedContext()));
+		}
+
+		if (!webFilter.description().isEmpty()) {
+			annotationsToAdd.add(ServiceDescription.Literal.of(webFilter.description()));
+		}
+
+		if (!webFilter.filterName().isEmpty()) {
+			annotationsToAdd.add(HttpWhiteboardFilterName.Literal.of(webFilter.filterName()));
+		}
+
+		if (webFilter.servletNames().length > 0) {
+			annotationsToAdd.add(HttpWhiteboardFilterServlet.Literal.of(webFilter.servletNames()));
+		}
+
+		if (webFilter.value().length > 0) {
+			annotationsToAdd.add(HttpWhiteboardFilterPattern.Literal.of(webFilter.value()));
+		}
+		else if (webFilter.urlPatterns().length > 0) {
+			annotationsToAdd.add(HttpWhiteboardFilterPattern.Literal.of(webFilter.urlPatterns()));
+		}
+
+		if (webFilter.dispatcherTypes().length > 0) {
+			annotationsToAdd.add(HttpWhiteboardFilterDispatcher.Literal.of(webFilter.dispatcherTypes()));
+		}
+
+		annotationsToAdd.add(HttpWhiteboardFilterAsyncSupported.Literal.of(webFilter.asyncSupported()));
+
+		if (!annotationsToAdd.isEmpty()) {
+			annotationsToAdd.forEach(pat.configureAnnotatedType()::add);
+		}
+	}
+
+	<X> void processWebListener(@Observes @WithAnnotations(WebListener.class) ProcessAnnotatedType<X> pat) {
+		final AnnotatedType<X> annotatedType = pat.getAnnotatedType();
+
+		WebListener webListener = annotatedType.getAnnotation(WebListener.class);
+
+		final Set<Annotation> annotationsToAdd = new HashSet<>();
+
+		if (!annotatedType.isAnnotationPresent(Service.class)) {
+			List<Class<?>> listenerTypes = new ArrayList<>();
+
+			Class<X> javaClass = annotatedType.getJavaClass();
+
+			if (javax.servlet.ServletContextListener.class.isAssignableFrom(javaClass)) {
+				listenerTypes.add(javax.servlet.ServletContextListener.class);
+			}
+			if (javax.servlet.ServletContextAttributeListener.class.isAssignableFrom(javaClass)) {
+				listenerTypes.add(javax.servlet.ServletContextAttributeListener.class);
+			}
+			if (javax.servlet.ServletRequestListener.class.isAssignableFrom(javaClass)) {
+				listenerTypes.add(javax.servlet.ServletRequestListener.class);
+			}
+			if (javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(javaClass)) {
+				listenerTypes.add(javax.servlet.ServletRequestAttributeListener.class);
+			}
+			if (javax.servlet.http.HttpSessionListener.class.isAssignableFrom(javaClass)) {
+				listenerTypes.add(javax.servlet.http.HttpSessionListener.class);
+			}
+			if (javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(javaClass)) {
+				listenerTypes.add(javax.servlet.http.HttpSessionAttributeListener.class);
+			}
+			if (javax.servlet.http.HttpSessionIdListener.class.isAssignableFrom(javaClass)) {
+				listenerTypes.add(javax.servlet.http.HttpSessionIdListener.class);
+			}
+
+			annotationsToAdd.add(Service.Literal.of(listenerTypes.toArray(new Class<?>[0])));
+		}
+
+		if(!annotatedType.isAnnotationPresent(HttpWhiteboardContextSelect.class)) {
+			annotationsToAdd.add(HttpWhiteboardContextSelect.Literal.of(getSelectedContext()));
+		}
+
+		annotationsToAdd.add(HttpWhiteboardListener.Literal.INSTANCE);
+
+		if (!webListener.value().isEmpty()) {
+			annotationsToAdd.add(ServiceDescription.Literal.of(webListener.value()));
+		}
+
+		if (!annotationsToAdd.isEmpty()) {
+			annotationsToAdd.forEach(pat.configureAnnotatedType()::add);
+		}
+	}
+
+	<X> void processWebServlet(@Observes @WithAnnotations(WebServlet.class) ProcessAnnotatedType<X> pat) {
+		final AnnotatedType<X> annotatedType = pat.getAnnotatedType();
+
+		WebServlet webServlet = annotatedType.getAnnotation(WebServlet.class);
+
+		final Set<Annotation> annotationsToAdd = new HashSet<>();
+
+		if (!annotatedType.isAnnotationPresent(Service.class)) {
+			annotationsToAdd.add(Service.Literal.of(new Class[] {Servlet.class}));
+		}
+
+		if(!annotatedType.isAnnotationPresent(HttpWhiteboardContextSelect.class)) {
+			annotationsToAdd.add(HttpWhiteboardContextSelect.Literal.of(getSelectedContext()));
+		}
+
+		if (!webServlet.name().isEmpty()) {
+			annotationsToAdd.add(HttpWhiteboardServletName.Literal.of(webServlet.name()));
+		}
+
+		if (webServlet.value().length > 0) {
+			annotationsToAdd.add(HttpWhiteboardServletPattern.Literal.of(webServlet.value()));
+		}
+		else if (webServlet.urlPatterns().length > 0) {
+			annotationsToAdd.add(HttpWhiteboardServletPattern.Literal.of(webServlet.urlPatterns()));
+		}
+
+		annotationsToAdd.add(ServiceRanking.Literal.of(webServlet.loadOnStartup()));
+
+		// TODO Howto: INIT PARAMS ???
+
+		annotationsToAdd.add(HttpWhiteboardServletAsyncSupported.Literal.of(webServlet.asyncSupported()));
+
+		if (!webServlet.description().isEmpty()) {
+			annotationsToAdd.add(ServiceDescription.Literal.of(webServlet.description()));
+		}
+
+		MultipartConfig multipartConfig = annotatedType.getAnnotation(MultipartConfig.class);
+
+		if (multipartConfig != null) {
+			annotationsToAdd.add(HttpWhiteboardServletMultipart.Literal.of(true, multipartConfig.fileSizeThreshold(), multipartConfig.location(), multipartConfig.maxFileSize(), multipartConfig.maxRequestSize()));
+		}
+
+		// TODO HowTo: ServletSecurity ???
+
+		if (!annotationsToAdd.isEmpty()) {
+			annotationsToAdd.forEach(pat.configureAnnotatedType()::add);
+		}
+	}
+
+	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");
+		properties.put(SERVICE_VENDOR, "Apache Software Foundation");
+		properties.put(HTTP_WHITEBOARD_CONTEXT_SELECT, getSelectedContext());
+		properties.put(HTTP_WHITEBOARD_LISTENER, Boolean.TRUE.toString());
+		properties.put(SERVICE_RANKING, Integer.MAX_VALUE - 100);
+
+		_listenerRegistration = _bundle.getBundleContext().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 Map<String, Object> getAttributes() {
+		BundleWiring bundleWiring = _bundle.adapt(BundleWiring.class);
+
+		List<BundleWire> wires = bundleWiring.getRequiredWires(EXTENDER_NAMESPACE);
+
+		Map<String, Object> cdiAttributes = Collections.emptyMap();
+
+		for (BundleWire wire : wires) {
+			BundleCapability capability = wire.getCapability();
+			Map<String, Object> attributes = capability.getAttributes();
+			String extender = (String)attributes.get(EXTENDER_NAMESPACE);
+
+			if (extender.equals(CDI_CAPABILITY_NAME)) {
+				BundleRequirement requirement = wire.getRequirement();
+				cdiAttributes = requirement.getAttributes();
+				break;
+			}
+		}
+
+		return cdiAttributes;
+	}
+
+	private String getSelectedContext() {
+		if (_contextSelect != null) {
+			return _contextSelect;
+		}
+
+		return _contextSelect = getSelectedContext0();
+	}
+
+	private String getSelectedContext0() {
+		Map<String, Object> attributes = getAttributes();
+
+		if (attributes.containsKey(HTTP_WHITEBOARD_CONTEXT_SELECT)) {
+			return (String)attributes.get(HTTP_WHITEBOARD_CONTEXT_SELECT);
+		}
+
+		Dictionary<String,String> headers = _bundle.getHeaders();
+
+		if (headers.get(WEB_CONTEXT_PATH) != null) {
+			return CONTEXT_PATH_PREFIX + headers.get(WEB_CONTEXT_PATH) + ')';
+		}
+
+		return DEFAULT_CONTEXT_FILTER;
+	}
+
+	private static final String CONTEXT_PATH_PREFIX = "(osgi.http.whiteboard.context.path=";
+	private static final String DEFAULT_CONTEXT_FILTER = "(osgi.http.whiteboard.context.name=default)";
+	private static final String[] LISTENER_CLASSES = new String[] {
+		ServletContextListener.class.getName(),
+		ServletRequestListener.class.getName(),
+		HttpSessionListener.class.getName()
+	};
+	private static final String WEB_CONTEXT_PATH = "Web-ContextPath";
+
+	private final Bundle _bundle;
+	private String _contextSelect;
+	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 CdiListener(final WebBeansContext webBeansContext) {
+			this.webBeansContext = webBeansContext;
+		}
+
+		@Override
+		public void contextInitialized(ServletContextEvent event) {
+			// update the sce to have the real one in CDI
+			try {
+				final Class<?> usc = event.getServletContext().getClassLoader()
+						.loadClass("org.apache.aries.cdi.container.internal.servlet.UpdatableServletContext");
+				final Object uscInstance = webBeansContext.getService(usc);
+				usc.getMethod("setDelegate", ServletContext.class)
+						.invoke(uscInstance, event.getServletContext());
+
+				// propagate attributes from the temporary sc
+				final ServletContext original = ServletContext.class.cast(usc.getMethod("getOriginal").invoke(uscInstance));
+				list(original.getAttributeNames())
+					.forEach(attr -> event.getServletContext().setAttribute(attr, original.getAttribute(attr)));
+			}
+			catch (final ClassNotFoundException | NoSuchMethodException | IllegalAccessException cnfe) {
+				// no-op, weirdly using another extender impl
+			}
+			catch (final InvocationTargetException ite) {
+				throw new IllegalStateException(ite.getTargetException());
+			}
+
+			// 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);
+			}
+		}
+	}
+}
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/WebExtensionFactory.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/WebExtensionFactory.java
new file mode 100644
index 0000000..8d1d045
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/WebExtensionFactory.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.aries.cdi.owb.web;
+
+import javax.enterprise.inject.spi.Extension;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.PrototypeServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+public class WebExtensionFactory implements PrototypeServiceFactory<Extension> {
+
+	@Override
+	public Extension getService(
+		Bundle bundle, ServiceRegistration<Extension> registration) {
+
+		return new WebExtension(bundle);
+	}
+
+	@Override
+	public void ungetService(
+		Bundle bundle, ServiceRegistration<Extension> registration, Extension service) {
+	}
+
+}
diff --git a/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/package-info.java b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/package-info.java
new file mode 100644
index 0000000..2312388
--- /dev/null
+++ b/cdi-owb/src/main/java/org/apache/aries/cdi/owb/web/package-info.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@org.osgi.annotation.bundle.Capability(
+	attribute = "objectClass:List<String>=javax.enterprise.inject.spi.Extension",
+	namespace = SERVICE_NAMESPACE
+)
+@org.osgi.annotation.bundle.Capability(
+	name = "aries.cdi.http",
+	namespace = CDI_EXTENSION_PROPERTY,
+	uses= {
+		javax.annotation.Priority.class,
+		javax.enterprise.context.spi.Context.class,
+		javax.enterprise.event.Observes.class,
+		javax.enterprise.inject.spi.Extension.class,
+		javax.servlet.ServletContextListener.class,
+		javax.servlet.http.HttpSessionListener.class
+	},
+	version = "1.0.0"
+)
+//Deliberately depend on Http Whiteboard version 1.0.0 (the spec annotation starts at 1.1.0)
+@org.osgi.annotation.bundle.Requirement(
+	name = "osgi.http",
+	namespace = IMPLEMENTATION_NAMESPACE,
+	version = "1.0.0",
+	resolution = OPTIONAL
+)
+@org.osgi.service.cdi.annotations.RequireCDIImplementation
+package org.apache.aries.cdi.owb.web;
+
+import static org.osgi.annotation.bundle.Requirement.Resolution.OPTIONAL;
+import static org.osgi.namespace.implementation.ImplementationNamespace.IMPLEMENTATION_NAMESPACE;
+import static org.osgi.namespace.service.ServiceNamespace.SERVICE_NAMESPACE;
+import static org.osgi.service.cdi.CDIConstants.CDI_EXTENSION_PROPERTY;
diff --git a/pom.xml b/pom.xml
index 8768ef8..a5958da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,8 +37,9 @@
 		<jsp.version>2.0</jsp.version>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 		<surefire.version>2.12</surefire.version>
-		<slf4j.version>1.7.25</slf4j.version>
+		<slf4j.version>1.7.28</slf4j.version>
 		<weld.version>3.0.5.Final</weld.version>
+		<owb.version>2.0.13-SNAPSHOT</owb.version>
 	</properties>
 
 	<licenses>
@@ -62,6 +63,7 @@
 		<module>cdi-extension-el-jsp</module>
 		<module>cdi-extension-http</module>
 		<module>cdi-extension-jndi</module>
+		<module>cdi-owb</module>
 		<module>cdi-bom</module>
 		<module>cdi-itests</module>
 		<module>cdi-executable</module>