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>