Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoakim Erdfelt2015-02-18 18:07:21 +0000
committerJoakim Erdfelt2015-03-12 17:09:52 +0000
commit31ee46d4825bec41ab0bd7aff2a458936b517321 (patch)
tree3f8847fb55aa149b848687a24bcb5834f71aea7a /jetty-cdi
parent3008ab85e543b46bff16f7193d19413f8a000b4b (diff)
downloadorg.eclipse.jetty.project-31ee46d4825bec41ab0bd7aff2a458936b517321.tar.gz
org.eclipse.jetty.project-31ee46d4825bec41ab0bd7aff2a458936b517321.tar.xz
org.eclipse.jetty.project-31ee46d4825bec41ab0bd7aff2a458936b517321.zip
453834 - CDI Support for WebSocket
+ Breaking down jetty-cdi into 3 modules * cdi-core * cdi-servlet * cdi-websocket + Creating WebSocketScope for cdi-websocket + Creating @Produces for jetty websocket api session and javax.websocket.Session + Unit tests for new functionality
Diffstat (limited to 'jetty-cdi')
-rw-r--r--jetty-cdi/cdi-core/pom.xml59
-rw-r--r--jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java28
-rw-r--r--jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/JettyLogFactory.java37
-rw-r--r--jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/NamedLiteral.java45
-rw-r--r--jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java34
-rw-r--r--jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstances.java25
-rw-r--r--jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/util/log/JettyLogHandler.java200
-rw-r--r--jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml6
-rw-r--r--jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java78
-rw-r--r--jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java112
-rw-r--r--jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LogFactory.java33
-rw-r--r--jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java46
-rw-r--r--jetty-cdi/cdi-core/src/test/resources/logging.properties2
-rw-r--r--jetty-cdi/cdi-servlet/pom.xml72
-rw-r--r--jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml19
-rw-r--r--jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod26
-rw-r--r--jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java131
-rw-r--r--jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java71
-rw-r--r--jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java57
-rw-r--r--jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java27
-rw-r--r--jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/IsoTimeFormatter.java39
-rw-r--r--jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/LocaleTimeFormatter.java38
-rw-r--r--jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestInfoServlet.java69
-rw-r--r--jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java71
-rw-r--r--jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java26
-rw-r--r--jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeServlet.java59
-rw-r--r--jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java115
-rw-r--r--jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml6
-rw-r--r--jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties11
-rw-r--r--jetty-cdi/cdi-servlet/src/test/resources/logging.properties2
-rw-r--r--jetty-cdi/cdi-websocket/pom.xml59
-rw-r--r--jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java44
-rw-r--r--jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java53
-rw-r--r--jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScope.java45
-rw-r--r--jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java112
-rw-r--r--jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContextHolder.java45
-rw-r--r--jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContextImpl.java83
-rw-r--r--jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java46
-rw-r--r--jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml4
-rw-r--r--jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension1
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java99
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java129
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java57
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java153
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/DataMaker.java34
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java92
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/BogusSession.java144
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/BogusSocket.java36
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/Food.java64
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/Meal.java40
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/WebSocketScopeBaselineTest.java116
-rw-r--r--jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/WebSocketScopeSessionTest.java251
-rw-r--r--jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml6
-rw-r--r--jetty-cdi/cdi-websocket/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension1
-rw-r--r--jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties11
-rw-r--r--jetty-cdi/cdi-websocket/src/test/resources/logging.properties2
-rw-r--r--jetty-cdi/pom.xml74
-rw-r--r--jetty-cdi/src/main/java/org/eclipse/jetty/cdi/JettyWeldInitializer.java6
-rw-r--r--jetty-cdi/src/test/java/org/eclipse/jetty/cdi/weld/cdiapp/CdiInfoSocket.java10
-rw-r--r--jetty-cdi/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension2
-rw-r--r--jetty-cdi/src/test/resources/jetty-logging.properties1
61 files changed, 3293 insertions, 71 deletions
diff --git a/jetty-cdi/cdi-core/pom.xml b/jetty-cdi/cdi-core/pom.xml
new file mode 100644
index 0000000000..f7f5a3f2de
--- /dev/null
+++ b/jetty-cdi/cdi-core/pom.xml
@@ -0,0 +1,59 @@
+<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">
+ <parent>
+ <groupId>org.eclipse.jetty.cdi</groupId>
+ <artifactId>jetty-cdi-parent</artifactId>
+ <version>9.3.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>cdi-core</artifactId>
+ <name>Jetty :: CDI :: Core</name>
+ <description>
+ Core CDI routines for Jetty (Also useful for CDI/SE applications that dont need a server)
+ </description>
+ <url>http://www.eclipse.org/jetty</url>
+ <packaging>jar</packaging>
+ <properties>
+ <bundle-symbolic-name>${project.groupId}.core</bundle-symbolic-name>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.weld</groupId>
+ <artifactId>weld-core</artifactId>
+ <version>${weld.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.weld.se</groupId>
+ <artifactId>weld-se-core</artifactId>
+ <version>${weld.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-test-helper</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>tests-jar</id>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java
new file mode 100644
index 0000000000..9f28671f30
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java
@@ -0,0 +1,28 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.core;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.util.AnnotationLiteral;
+
+@SuppressWarnings("serial")
+public class AnyLiteral extends AnnotationLiteral<Any>
+{
+ public static final AnyLiteral INSTANCE = new AnyLiteral();
+}
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/JettyLogFactory.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/JettyLogFactory.java
new file mode 100644
index 0000000000..8366bbc2fd
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/JettyLogFactory.java
@@ -0,0 +1,37 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.core;
+
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * CDI Producer of Jetty Logging instances.
+ */
+public class JettyLogFactory
+{
+ @Produces
+ public Logger createLogger(InjectionPoint injectionPoint)
+ {
+ return Log.getLogger(injectionPoint.getMember().getDeclaringClass());
+ }
+}
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/NamedLiteral.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/NamedLiteral.java
new file mode 100644
index 0000000000..fdb3b3e224
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/NamedLiteral.java
@@ -0,0 +1,45 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.core;
+
+import javax.enterprise.util.AnnotationLiteral;
+import javax.inject.Named;
+
+@SuppressWarnings("serial")
+public class NamedLiteral extends AnnotationLiteral<Named> implements Named
+{
+ private final String value;
+
+ public String value()
+ {
+ return value;
+ }
+
+ public NamedLiteral(String name)
+ {
+ if (name == null)
+ {
+ this.value = "";
+ }
+ else
+ {
+ this.value = name;
+ }
+ }
+} \ No newline at end of file
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java
new file mode 100644
index 0000000000..8babda4135
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java
@@ -0,0 +1,34 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.core;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+
+public class ScopedInstance<T>
+{
+ public Bean<T> bean;
+ public CreationalContext<T> creationalContext;
+ public T instance;
+
+ public void destroy()
+ {
+ bean.destroy(instance,creationalContext);
+ }
+}
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstances.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstances.java
new file mode 100644
index 0000000000..e491583e68
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstances.java
@@ -0,0 +1,25 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.core;
+
+import java.util.LinkedList;
+
+public class ScopedInstances extends LinkedList<ScopedInstance<?>>
+{
+} \ No newline at end of file
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/util/log/JettyLogHandler.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/util/log/JettyLogHandler.java
new file mode 100644
index 0000000000..fbee0f3640
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/util/log/JettyLogHandler.java
@@ -0,0 +1,200 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.util.log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.regex.Pattern;
+
+import org.eclipse.jetty.util.log.Log;
+
+/**
+ * Redirect java.util.logging events to Jetty Log
+ */
+public class JettyLogHandler extends java.util.logging.Handler
+{
+ public static void config()
+ {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ URL url = cl.getResource("logging.properties");
+ if (url != null)
+ {
+ System.err.printf("Initializing java.util.logging from %s%n",url);
+ try (InputStream in = url.openStream())
+ {
+ LogManager.getLogManager().readConfiguration(in);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace(System.err);
+ }
+ }
+ else
+ {
+ System.err.printf("WARNING: java.util.logging failed to initialize: logging.properties not found%n");
+ }
+
+ System.setProperty("org.apache.commons.logging.Log","org.apache.commons.logging.impl.Jdk14Logger");
+ }
+
+ public JettyLogHandler()
+ {
+ if (Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.DEBUG","false")))
+ {
+ setLevel(Level.FINEST);
+ }
+
+ if (Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.IGNORED","false")))
+ {
+ setLevel(Level.ALL);
+ }
+
+ System.err.printf("%s Initialized at level [%s]%n",this.getClass().getName(),getLevel().getName());
+ }
+
+ private synchronized String formatMessage(LogRecord record)
+ {
+ String msg = getMessage(record);
+
+ try
+ {
+ Object params[] = record.getParameters();
+ if ((params == null) || (params.length == 0))
+ {
+ return msg;
+ }
+
+ if (Pattern.compile("\\{\\d+\\}").matcher(msg).find())
+ {
+ return MessageFormat.format(msg,params);
+ }
+
+ return msg;
+ }
+ catch (Exception ex)
+ {
+ return msg;
+ }
+ }
+
+ private String getMessage(LogRecord record)
+ {
+ ResourceBundle bundle = record.getResourceBundle();
+ if (bundle != null)
+ {
+ try
+ {
+ return bundle.getString(record.getMessage());
+ }
+ catch (java.util.MissingResourceException ex)
+ {
+ }
+ }
+
+ return record.getMessage();
+ }
+
+ @Override
+ public void publish(LogRecord record)
+ {
+ org.eclipse.jetty.util.log.Logger JLOG = getJettyLogger(record.getLoggerName());
+
+ int level = record.getLevel().intValue();
+ if (level >= Level.OFF.intValue())
+ {
+ // nothing to log, skip it.
+ return;
+ }
+
+ Throwable cause = record.getThrown();
+ String msg = formatMessage(record);
+
+ if (level >= Level.WARNING.intValue())
+ {
+ // log at warn
+ if (cause != null)
+ {
+ JLOG.warn(msg,cause);
+ }
+ else
+ {
+ JLOG.warn(msg);
+ }
+ return;
+ }
+
+ if (level >= Level.INFO.intValue())
+ {
+ // log at info
+ if (cause != null)
+ {
+ JLOG.info(msg,cause);
+ }
+ else
+ {
+ JLOG.info(msg);
+ }
+ return;
+ }
+
+ if (level >= Level.FINEST.intValue())
+ {
+ // log at debug
+ if (cause != null)
+ {
+ JLOG.debug(msg,cause);
+ }
+ else
+ {
+ JLOG.debug(msg);
+ }
+ return;
+ }
+
+ if (level >= Level.ALL.intValue())
+ {
+ // only corresponds with ignore (in jetty speak)
+ JLOG.ignore(cause);
+ return;
+ }
+ }
+
+ private Logger getJettyLogger(String loggerName)
+ {
+ return org.eclipse.jetty.util.log.Log.getLogger(loggerName);
+ }
+
+ @Override
+ public void flush()
+ {
+ // ignore
+ }
+
+ @Override
+ public void close() throws SecurityException
+ {
+ // ignore
+ }
+}
diff --git a/jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml b/jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000000..f158a71b6e
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+ http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
+ bean-discovery-mode="all">
+</beans> \ No newline at end of file
diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java
new file mode 100644
index 0000000000..6e56797202
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java
@@ -0,0 +1,78 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.core;
+
+import java.util.Set;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+
+import org.jboss.weld.environment.se.Weld;
+import org.jboss.weld.environment.se.WeldContainer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public abstract class AbstractWeldTest
+{
+ public static class TestBean<T>
+ {
+ public Bean<T> bean;
+ public CreationalContext<T> cCtx;
+ public T instance;
+
+ public void destroy()
+ {
+ bean.destroy(instance,cCtx);
+ }
+ }
+
+ @BeforeClass
+ public static void initWeld()
+ {
+ weld = new Weld();
+ container = weld.initialize();
+ }
+
+ @AfterClass
+ public static void shutdownWeld()
+ {
+ weld.shutdown();
+ }
+
+ private static WeldContainer container;
+ private static Weld weld;
+
+ @SuppressWarnings("unchecked")
+ public <T> TestBean<T> newInstance(Class<T> clazz) throws Exception
+ {
+ TestBean<T> testBean = new TestBean<>();
+ Set<Bean<?>> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE);
+ if (beans.size() > 0)
+ {
+ testBean.bean = (Bean<T>)beans.iterator().next();
+ testBean.cCtx = container.getBeanManager().createCreationalContext(testBean.bean);
+ testBean.instance = (T)container.getBeanManager().getReference(testBean.bean,clazz,testBean.cCtx);
+ return testBean;
+ }
+ else
+ {
+ throw new Exception(String.format("Can't find class %s",clazz));
+ }
+ }
+}
diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java
new file mode 100644
index 0000000000..b77f2e367e
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java
@@ -0,0 +1,112 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.core.logging;
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.regex.Pattern;
+
+public class LeanConsoleHandler extends Handler
+{
+ public static Handler createWithLevel(Level level)
+ {
+ LeanConsoleHandler handler = new LeanConsoleHandler();
+ handler.setLevel(level);
+ return handler;
+ }
+
+ @Override
+ public void close() throws SecurityException
+ {
+ /* nothing to do here */
+ }
+
+ @Override
+ public void flush()
+ {
+ /* nothing to do here */
+ }
+
+ public synchronized String formatMessage(LogRecord record)
+ {
+ String msg = getMessage(record);
+
+ try
+ {
+ Object params[] = record.getParameters();
+ if ((params == null) || (params.length == 0))
+ {
+ return msg;
+ }
+
+ if (Pattern.compile("\\{\\d+\\}").matcher(msg).find())
+ {
+ return MessageFormat.format(msg,params);
+ }
+
+ return msg;
+ }
+ catch (Exception ex)
+ {
+ return msg;
+ }
+ }
+
+ private String getMessage(LogRecord record)
+ {
+ ResourceBundle bundle = record.getResourceBundle();
+ if (bundle != null)
+ {
+ try
+ {
+ return bundle.getString(record.getMessage());
+ }
+ catch (java.util.MissingResourceException ex)
+ {
+ }
+ }
+
+ return record.getMessage();
+ }
+
+ @Override
+ public void publish(LogRecord record)
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append("[").append(record.getLevel().getName()).append("] ");
+ String logname = record.getLoggerName();
+ int idx = logname.lastIndexOf('.');
+ if (idx > 0)
+ {
+ logname = logname.substring(idx + 1);
+ }
+ buf.append(logname);
+ buf.append(": ");
+ buf.append(formatMessage(record));
+
+ System.out.println(buf.toString());
+ if (record.getThrown() != null)
+ {
+ record.getThrown().printStackTrace(System.out);
+ }
+ }
+}
diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LogFactory.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LogFactory.java
new file mode 100644
index 0000000000..9918914c9b
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LogFactory.java
@@ -0,0 +1,33 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.core.logging;
+
+import java.util.logging.Logger;
+
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+
+public class LogFactory
+{
+ @Produces
+ public Logger createLogger(InjectionPoint injectionPoint)
+ {
+ return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
+ }
+}
diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java
new file mode 100644
index 0000000000..8e3bfcf64e
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java
@@ -0,0 +1,46 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.core.logging;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.logging.LogManager;
+
+public class Logging
+{
+ public static void config()
+ {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ URL url = cl.getResource("logging.properties");
+ if (url != null)
+ {
+ try (InputStream in = url.openStream())
+ {
+ LogManager.getLogManager().readConfiguration(in);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace(System.err);
+ }
+ }
+
+ System.setProperty("org.apache.commons.logging.Log","org.apache.commons.logging.impl.Jdk14Logger");
+ }
+}
diff --git a/jetty-cdi/cdi-core/src/test/resources/logging.properties b/jetty-cdi/cdi-core/src/test/resources/logging.properties
new file mode 100644
index 0000000000..c0ff63eb82
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/resources/logging.properties
@@ -0,0 +1,2 @@
+handlers = org.eclipse.jetty.cdi.core.logging.LeanConsoleHandler
+.level=INFO
diff --git a/jetty-cdi/cdi-servlet/pom.xml b/jetty-cdi/cdi-servlet/pom.xml
new file mode 100644
index 0000000000..05e9d3d4e5
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/pom.xml
@@ -0,0 +1,72 @@
+<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">
+ <parent>
+ <groupId>org.eclipse.jetty.cdi</groupId>
+ <artifactId>jetty-cdi-parent</artifactId>
+ <version>9.3.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>cdi-servlet</artifactId>
+ <name>Jetty :: CDI :: Servlet</name>
+ <url>http://www.eclipse.org/jetty</url>
+ <packaging>jar</packaging>
+ <properties>
+ <weld.version>2.2.9.Final</weld.version>
+ <bundle-symbolic-name>${project.groupId}.servlet</bundle-symbolic-name>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>config</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.jetty.cdi</groupId>
+ <artifactId>cdi-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-plus</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-deploy</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.weld.servlet</groupId>
+ <artifactId>weld-servlet</artifactId>
+ <version>${weld.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>apache-jsp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- below here lie testing dragons -->
+ <dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-test-helper</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml b/jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml
new file mode 100644
index 0000000000..d364f4c45a
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+
+<!-- =============================================================== -->
+<!-- Mixin the Weld / CDI classes to the class loader -->
+<!-- =============================================================== -->
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+ <Ref refid="DeploymentManager">
+ <Call name="addLifeCycleBinding">
+ <Arg>
+ <New
+ class="org.eclipse.jetty.cdi.WeldDeploymentBinding">
+ </New>
+ </Arg>
+ </Call>
+ </Ref>
+</Configure>
+
diff --git a/jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod b/jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod
new file mode 100644
index 0000000000..37bca3c550
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod
@@ -0,0 +1,26 @@
+#
+# CDI / Weld Jetty module
+#
+
+[depend]
+deploy
+annotations
+plus
+# JSP (and EL) are requirements for CDI and Weld
+jsp
+
+[files]
+lib/weld/
+maven://org.jboss.weld.servlet/weld-servlet/2.2.9.Final|lib/weld/weld-servlet-2.2.9.Final.jar
+
+[lib]
+lib/weld/weld-servlet-2.2.9.Final.jar
+lib/jetty-cdi-${jetty.version}.jar
+
+[xml]
+etc/jetty-cdi.xml
+
+[license]
+Weld is an open source project hosted on Github and released under the Apache 2.0 license.
+http://weld.cdi-spec.org/
+http://www.apache.org/licenses/LICENSE-2.0.html
diff --git a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java
new file mode 100644
index 0000000000..8c1c5d2f84
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java
@@ -0,0 +1,131 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.jboss.weld.environment.servlet.EnhancedListener;
+
+/**
+ * Handy {@link ServletContextHandler} implementation that hooks up
+ * all of the various CDI related components and listeners from Weld.
+ */
+public class EmbeddedCdiHandler extends ServletContextHandler
+{
+ private static final Logger LOG = Log.getLogger(EmbeddedCdiHandler.class);
+
+ private static final String[] REQUIRED_BEANS_XML_PATHS = new String[] {
+ "/WEB-INF/beans.xml",
+ "/META-INF/beans.xml",
+ "/WEB-INF/classes/META-INF/beans.xml"
+ };
+
+ public EmbeddedCdiHandler()
+ {
+ super();
+ }
+
+ public EmbeddedCdiHandler(int options)
+ {
+ super(options);
+ }
+
+ @Override
+ protected void doStart() throws Exception
+ {
+ // Required of CDI
+ Resource baseResource = getBaseResource();
+ if (baseResource == null)
+ {
+ throw new NullPointerException("baseResource must be set (to so it can find the beans.xml)");
+ }
+
+ boolean foundBeansXml = false;
+
+ // Verify that beans.xml is present, otherwise weld will fail silently.
+ for(String beansXmlPath: REQUIRED_BEANS_XML_PATHS) {
+ Resource res = baseResource.addPath(beansXmlPath);
+ if (res == null)
+ {
+ // not found, skip it
+ continue;
+ }
+
+ if (res.exists())
+ {
+ foundBeansXml = true;
+ }
+
+ if (res.isDirectory())
+ {
+ throw new IOException("Directory conflicts with expected file: " + res.getURI().toASCIIString());
+ }
+ }
+
+ if (!foundBeansXml)
+ {
+ StringBuilder err = new StringBuilder();
+ err.append("Unable to find required beans.xml from the baseResource: ");
+ err.append(baseResource.getURI().toASCIIString()).append(System.lineSeparator());
+ err.append("Searched for: ");
+ for (String beansXmlPath : REQUIRED_BEANS_XML_PATHS)
+ {
+ err.append(System.lineSeparator());
+ err.append(" ").append(beansXmlPath);
+ }
+ LOG.warn("ERROR: {}",err.toString());
+ throw new IOException(err.toString());
+ }
+
+ // Initialize Weld
+ JettyWeldInitializer.initContext(this);
+
+ // Wire up Weld (what's usually done via the ServletContainerInitializer)
+ ServletContext ctx = getServletContext();
+
+ // Fake the call to ServletContainerInitializer
+ ClassLoader orig = Thread.currentThread().getContextClassLoader();
+ try
+ {
+ Thread.currentThread().setContextClassLoader(ctx.getClassLoader());
+
+ EnhancedListener weldListener = new EnhancedListener();
+ Set<Class<?>> classes = Collections.emptySet();
+ weldListener.onStartup(classes,ctx);
+
+ // add the rest of the Weld Listeners
+ ctx.addListener(weldListener);
+ }
+ finally
+ {
+ Thread.currentThread().setContextClassLoader(orig);
+ }
+
+ // Let normal ServletContextHandler startup continue its merry way
+ super.doStart();
+ }
+}
diff --git a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java
new file mode 100644
index 0000000000..08694d2310
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java
@@ -0,0 +1,71 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+
+import org.eclipse.jetty.plus.jndi.Resource;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * Utility class suitable for initializing CDI/Weld on Embedded Jetty
+ */
+public class JettyWeldInitializer
+{
+ /**
+ * Initialize WebAppContext to support CDI/Weld.
+ * <p>
+ * Initializes Context, then sets up WebAppContext system and server classes to allow Weld to operate from Server
+ * level.
+ * <p>
+ * Includes {@link #initContext(ContextHandler)} behavior as well.
+ */
+ public static void initWebApp(WebAppContext webapp) throws NamingException
+ {
+ initContext(webapp);
+
+ // webapp cannot change / replace weld classes
+ webapp.addSystemClass("org.jboss.weld.");
+ webapp.addSystemClass("org.jboss.classfilewriter.");
+ webapp.addSystemClass("org.jboss.logging.");
+ webapp.addSystemClass("com.google.common.");
+
+ // don't hide weld classes from webapps (allow webapp to use ones from system classloader)
+ webapp.addServerClass("-org.jboss.weld.");
+ webapp.addServerClass("-org.jboss.classfilewriter.");
+ webapp.addServerClass("-org.jboss.logging.");
+ webapp.addServerClass("-com.google.common.");
+ }
+
+ public static void initContext(ContextHandler handler) throws NamingException
+ {
+ // TODO: handler.addLifeCycleListener(new WebSocketServerLifecycleListener(handler));
+
+ // Add context specific weld container reference.
+ // See https://issues.jboss.org/browse/WELD-1710
+ // and https://github.com/weld/core/blob/2.2.5.Final/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/WeldServletLifecycle.java#L244-L253
+ handler.setInitParameter("org.jboss.weld.environment.container.class","org.jboss.weld.environment.jetty.JettyContainer");
+
+ // Setup Weld BeanManager reference
+ Reference ref = new Reference("javax.enterprise.inject.spi.BeanManager","org.jboss.weld.resources.ManagerObjectFactory",null);
+ new Resource(handler,"BeanManager",ref);
+ }
+}
diff --git a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java
new file mode 100644
index 0000000000..cd365fff48
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java
@@ -0,0 +1,57 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import org.eclipse.jetty.deploy.App;
+import org.eclipse.jetty.deploy.AppLifeCycle;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * Perform some basic weld configuration of WebAppContext
+ */
+public class WeldDeploymentBinding implements AppLifeCycle.Binding
+{
+ public String[] getBindingTargets()
+ {
+ return new String[] { "deploying" };
+ }
+
+ public void processBinding(Node node, App app) throws Exception
+ {
+ ContextHandler handler = app.getContextHandler();
+ if (handler == null)
+ {
+ throw new NullPointerException("No Handler created for App: " + app);
+ }
+
+ if (handler instanceof WebAppContext)
+ {
+ // Do webapp specific init
+ WebAppContext webapp = (WebAppContext)handler;
+ JettyWeldInitializer.initWebApp(webapp);
+ }
+ else
+ {
+ // Do general init
+ JettyWeldInitializer.initContext(handler);
+ }
+ }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java
new file mode 100644
index 0000000000..a7ff5c82da
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java
@@ -0,0 +1,27 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public interface Dumper
+{
+ public void dump(PrintWriter out) throws IOException;
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/IsoTimeFormatter.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/IsoTimeFormatter.java
new file mode 100644
index 0000000000..2ff054e6c5
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/IsoTimeFormatter.java
@@ -0,0 +1,39 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.inject.Named;
+
+@Named("iso")
+public class IsoTimeFormatter implements TimeFormatter
+{
+ @Override
+ public String format(Calendar cal)
+ {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",Locale.US);
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return dateFormat.format(cal.getTime());
+ }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/LocaleTimeFormatter.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/LocaleTimeFormatter.java
new file mode 100644
index 0000000000..9e74d767f3
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/LocaleTimeFormatter.java
@@ -0,0 +1,38 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import javax.enterprise.inject.Default;
+import javax.inject.Named;
+
+@Named("locale")
+@Default
+public class LocaleTimeFormatter implements TimeFormatter
+{
+ public static final TimeFormatter INSTANCE = new LocaleTimeFormatter();
+
+ @Override
+ public String format(Calendar cal)
+ {
+ return new SimpleDateFormat().format(cal.getTime());
+ }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestInfoServlet.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestInfoServlet.java
new file mode 100644
index 0000000000..20b4cf98ae
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestInfoServlet.java
@@ -0,0 +1,69 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.cdi.core.NamedLiteral;
+
+@SuppressWarnings("serial")
+@WebServlet("/req-info")
+public class RequestInfoServlet extends HttpServlet
+{
+ @Inject
+ @Any
+ private Instance<Dumper> dumpers;
+
+ @Inject
+ @Named("params")
+ private Dumper defaultDumper;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ resp.setContentType("text/plain");
+ PrintWriter out = resp.getWriter();
+
+ Dumper dumper = defaultDumper;
+
+ String dumperId = req.getParameter("dumperId");
+
+ if (dumperId != null)
+ {
+ Instance<Dumper> inst = dumpers.select(new NamedLiteral(dumperId));
+ if (!inst.isAmbiguous() && !inst.isUnsatisfied())
+ {
+ dumper = inst.get();
+ }
+ }
+
+ dumper.dump(out);
+ }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java
new file mode 100644
index 0000000000..53291efc55
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java
@@ -0,0 +1,71 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.http.HttpServletRequest;
+
+@Named("params")
+@RequestScoped
+public class RequestParamsDumper implements Dumper
+{
+ @Inject
+ private HttpServletRequest request;
+
+ @Override
+ public void dump(PrintWriter out) throws IOException
+ {
+ out.printf("request is %s%n",request == null ? "NULL" : "PRESENT");
+
+ if (request != null)
+ {
+ Map<String, String[]> params = request.getParameterMap();
+ List<String> paramNames = new ArrayList<>();
+ paramNames.addAll(params.keySet());
+ Collections.sort(paramNames);
+
+ out.printf("parameters.size = [%d]%n",params.size());
+
+ for (String name : paramNames)
+ {
+ out.printf(" param[%s] = [",name);
+ boolean delim = false;
+ for (String val : params.get(name))
+ {
+ if (delim)
+ {
+ out.print(", ");
+ }
+ out.print(val);
+ delim = true;
+ }
+ out.println("]");
+ }
+ }
+ }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java
new file mode 100644
index 0000000000..0bd5b75313
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java
@@ -0,0 +1,26 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import java.util.Calendar;
+
+public interface TimeFormatter
+{
+ public String format(Calendar cal);
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeServlet.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeServlet.java
new file mode 100644
index 0000000000..db8260950e
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeServlet.java
@@ -0,0 +1,59 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import java.io.IOException;
+import java.util.Calendar;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.cdi.core.NamedLiteral;
+
+@SuppressWarnings("serial")
+@WebServlet(urlPatterns = "/time")
+public class TimeServlet extends HttpServlet
+{
+ @Inject
+ @Any
+ Instance<TimeFormatter> formatters;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ resp.setContentType("text/plain");
+
+ String timeType = req.getParameter("type");
+ TimeFormatter time = LocaleTimeFormatter.INSTANCE;
+
+ Instance<TimeFormatter> inst = formatters.select(new NamedLiteral(timeType));
+ if (!inst.isAmbiguous() && !inst.isUnsatisfied())
+ {
+ time = inst.get();
+ }
+
+ resp.getWriter().println(time.format(Calendar.getInstance()));
+ }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java
new file mode 100644
index 0000000000..f307d438a2
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java
@@ -0,0 +1,115 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.servlet;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.net.URI;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.SimpleRequest;
+import org.eclipse.jetty.util.log.JettyLogHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class WeldInitializationTest
+{
+ private static final Logger LOG = Log.getLogger(WeldInitializationTest.class);
+ private static Server server;
+ private static URI serverHttpURI;
+
+ @BeforeClass
+ public static void startServer() throws Exception
+ {
+ JettyLogHandler.config();
+
+ server = new Server();
+ ServerConnector connector = new ServerConnector(server);
+ connector.setPort(0);
+ server.addConnector(connector);
+
+ EmbeddedCdiHandler context = new EmbeddedCdiHandler();
+
+ File baseDir = MavenTestingUtils.getTestResourcesDir();
+
+ context.setBaseResource(Resource.newResource(baseDir));
+ context.setContextPath("/");
+ server.setHandler(context);
+
+ // Add some servlets
+ context.addServlet(TimeServlet.class,"/time");
+ context.addServlet(RequestInfoServlet.class,"/req-info");
+
+ server.start();
+
+ String host = connector.getHost();
+ if (host == null)
+ {
+ host = "localhost";
+ }
+ int port = connector.getLocalPort();
+ serverHttpURI = new URI(String.format("http://%s:%d/",host,port));
+ }
+
+ @AfterClass
+ public static void stopServer()
+ {
+ try
+ {
+ server.stop();
+ }
+ catch (Exception e)
+ {
+ LOG.warn(e);
+ }
+ }
+
+ @Test
+ public void testRequestParamServletDefault() throws Exception
+ {
+ SimpleRequest req = new SimpleRequest(serverHttpURI);
+ String resp = req.getString("req-info");
+
+ System.out.println(resp);
+
+ assertThat("Response",resp,containsString("request is PRESENT"));
+ assertThat("Response",resp,containsString("parameters.size = [0]"));
+ }
+
+ @Test
+ public void testRequestParamServletAbc() throws Exception
+ {
+ SimpleRequest req = new SimpleRequest(serverHttpURI);
+ String resp = req.getString("req-info?abc=123");
+
+ System.out.println(resp);
+
+ assertThat("Response",resp,containsString("request is PRESENT"));
+ assertThat("Response",resp,containsString("parameters.size = [1]"));
+ assertThat("Response",resp,containsString(" param[abc] = [123]"));
+ }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml b/jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml
new file mode 100644
index 0000000000..f158a71b6e
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+ http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
+ bean-discovery-mode="all">
+</beans> \ No newline at end of file
diff --git a/jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties b/jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000000..f69b351e50
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties
@@ -0,0 +1,11 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.jboss.LEVEL=DEBUG
+org.eclipse.jetty.LEVEL=INFO
+
+org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
+org.eclipse.jetty.cdi.LEVEL=DEBUG
+
+# org.eclipse.jetty.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.client.LEVEL=DEBUG
+
diff --git a/jetty-cdi/cdi-servlet/src/test/resources/logging.properties b/jetty-cdi/cdi-servlet/src/test/resources/logging.properties
new file mode 100644
index 0000000000..cfec8c7ab5
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/resources/logging.properties
@@ -0,0 +1,2 @@
+handlers = org.eclipse.jetty.util.log.JettyLogHandler
+.level=FINE
diff --git a/jetty-cdi/cdi-websocket/pom.xml b/jetty-cdi/cdi-websocket/pom.xml
new file mode 100644
index 0000000000..e44eaff38b
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/pom.xml
@@ -0,0 +1,59 @@
+<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">
+ <parent>
+ <groupId>org.eclipse.jetty.cdi</groupId>
+ <artifactId>jetty-cdi-parent</artifactId>
+ <version>9.3.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>cdi-websocket</artifactId>
+ <name>Jetty :: CDI :: WebSocket</name>
+ <url>http://www.eclipse.org/jetty</url>
+ <packaging>jar</packaging>
+ <properties>
+ <weld.version>2.2.9.Final</weld.version>
+ <bundle-symbolic-name>${project.groupId}.websocket</bundle-symbolic-name>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.jetty.cdi</groupId>
+ <artifactId>cdi-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.websocket</groupId>
+ <artifactId>websocket-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- below here lie testing dragons -->
+ <dependency>
+ <groupId>org.jboss.weld.se</groupId>
+ <artifactId>weld-se-core</artifactId>
+ <version>${weld.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.cdi</groupId>
+ <artifactId>cdi-core</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.cdi</groupId>
+ <artifactId>cdi-servlet</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.websocket</groupId>
+ <artifactId>javax-websocket-server-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-test-helper</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java
new file mode 100644
index 0000000000..a720976f77
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java
@@ -0,0 +1,44 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket;
+
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.websocket.Session;
+
+public class JavaWebSocketSessionProducer
+{
+ private ThreadLocal<Session> sessionInstance;
+
+ public JavaWebSocketSessionProducer()
+ {
+ sessionInstance = new ThreadLocal<Session>();
+ }
+
+ public void setSession(Session sess)
+ {
+ sessionInstance.set(sess);
+ }
+
+ @Produces
+ public Session getSession(InjectionPoint injectionPoint)
+ {
+ return this.sessionInstance.get();
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java
new file mode 100644
index 0000000000..3b89f55da3
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java
@@ -0,0 +1,53 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket;
+
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.inject.Singleton;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.Session;
+
+@Singleton
+public class JettyWebSocketSessionProducer
+{
+ private static final Logger LOG = Log.getLogger(JettyWebSocketSessionProducer.class);
+ private ThreadLocal<Session> sessionInstance;
+
+ public JettyWebSocketSessionProducer()
+ {
+ LOG.debug("ctor<>");
+ sessionInstance = new ThreadLocal<Session>();
+ }
+
+ public void setSession(Session sess)
+ {
+ LOG.debug("setSession()");
+ sessionInstance.set(sess);
+ }
+
+ @Produces
+ public Session getSession(InjectionPoint injectionPoint)
+ {
+ LOG.debug("getSession({})",injectionPoint);
+ return this.sessionInstance.get();
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScope.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScope.java
new file mode 100644
index 0000000000..1bdaa43a03
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScope.java
@@ -0,0 +1,45 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Scope;
+
+/**
+ * A CDI Context Scope for a WebSocket Session / Endpoint
+ * <p>
+ * <em>CAUTION: This is a highly speculative scope defined by Jetty. One that will likely be replaced by a formal spec later</em>
+ * <p>
+ * At the time of implementation (of this scope), no standard scope exists for websocket session lifecycle.
+ */
+@Scope
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
+@Inherited
+@Documented
+public @interface WebSocketScope
+{
+
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java
new file mode 100644
index 0000000000..561e6fb043
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java
@@ -0,0 +1,112 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket;
+
+import java.util.Set;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+
+import org.eclipse.jetty.cdi.core.AnyLiteral;
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+import org.eclipse.jetty.cdi.core.ScopedInstances;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.Session;
+
+@Dependent
+public class WebSocketScopeContext
+{
+ private static final Logger LOG = Log.getLogger(WebSocketScopeContext.class);
+ public static ThreadLocal<ScopedInstances> state = new ThreadLocal<>();
+
+ private ScopedInstances scope;
+
+ @Inject
+ private BeanManager beanManager;
+
+ @Inject
+ private JettyWebSocketSessionProducer jettySessionProducer;
+
+ @Inject
+ private JavaWebSocketSessionProducer javaSessionProducer;
+
+ public void begin()
+ {
+ LOG.debug("begin()");
+ if (state.get() != null)
+ {
+ throw new IllegalAccessError("Already in WebSocketScope");
+ }
+ state.set(scope);
+ }
+
+ public void create()
+ {
+ LOG.debug("create()");
+ scope = new ScopedInstances();
+ }
+
+ public void destroy()
+ {
+ LOG.debug("destroy()");
+ for (ScopedInstance<?> entry : scope)
+ {
+ entry.destroy();
+ }
+ }
+
+ public void end()
+ {
+ LOG.debug("end()");
+ if (state.get() == null)
+ {
+ throw new IllegalAccessError("Not in WebSocketScope");
+ }
+ state.remove();
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public <T> T newInstance(Class<T> clazz)
+ {
+ LOG.debug("newInstance()");
+ Set<Bean<?>> beans = beanManager.getBeans(clazz,AnyLiteral.INSTANCE);
+ if (beans.isEmpty())
+ {
+ return null;
+ }
+
+ Bean bean = beans.iterator().next();
+ CreationalContext cc = beanManager.createCreationalContext(bean);
+ return (T)beanManager.getReference(bean,clazz,cc);
+ }
+
+ public void setSession(Session sess)
+ {
+ LOG.debug("setSession()");
+ jettySessionProducer.setSession(sess);
+ if(sess instanceof javax.websocket.Session)
+ {
+ javaSessionProducer.setSession((javax.websocket.Session)sess);
+ }
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContextHolder.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContextHolder.java
new file mode 100644
index 0000000000..a184047f39
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContextHolder.java
@@ -0,0 +1,45 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket;
+
+import java.util.Map;
+
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+
+public class WebSocketScopeContextHolder
+{
+ public <T> Map<Class<T>,ScopedInstance<T>> getBeans()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public <T> ScopedInstance<T> getBean(Class<T> beanClass)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void putBean(ScopedInstance customInstance)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContextImpl.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContextImpl.java
new file mode 100644
index 0000000000..44f7b8cd8a
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContextImpl.java
@@ -0,0 +1,83 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket;
+
+import java.lang.annotation.Annotation;
+
+import javax.enterprise.context.spi.Context;
+import javax.enterprise.context.spi.Contextual;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.inject.Inject;
+
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+import org.eclipse.jetty.util.log.Logger;
+
+public class WebSocketScopeContextImpl implements Context
+{
+ @Inject
+ private Logger LOG;
+
+ private WebSocketScopeContextHolder customScopeContextHolder;
+
+ @Override
+ public <T> T get(Contextual<T> contextual)
+ {
+ LOG.debug(".get({})",contextual);
+
+ Bean bean = (Bean) contextual;
+ if (customScopeContextHolder.getBeans().containsKey(bean.getBeanClass())) {
+ return (T) customScopeContextHolder.getBean(bean.getBeanClass()).instance;
+ }
+
+ return null;
+ }
+
+ @Override
+ public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
+ {
+ LOG.debug(".get({},{})",contextual,creationalContext);
+ // TODO Auto-generated method stub
+
+ Bean bean = (Bean) contextual;
+ if (customScopeContextHolder.getBeans().containsKey(bean.getBeanClass())) {
+ return (T) customScopeContextHolder.getBean(bean.getBeanClass()).instance;
+ }
+
+ T t = (T) bean.create(creationalContext);
+ ScopedInstance customInstance = new ScopedInstance();
+ customInstance.bean = bean;
+ customInstance.creationalContext = creationalContext;
+ customInstance.instance = t;
+ customScopeContextHolder.putBean(customInstance);
+ return t;
+ }
+
+ @Override
+ public Class<? extends Annotation> getScope()
+ {
+ return WebSocketScope.class;
+ }
+
+ @Override
+ public boolean isActive()
+ {
+ return true;
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java
new file mode 100644
index 0000000000..b17cc360a5
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java
@@ -0,0 +1,46 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class WebSocketScopeExtension implements Extension
+{
+ private static final Logger LOG = Log.getLogger(WebSocketScopeExtension.class);
+
+ public void addScope(@Observes final BeforeBeanDiscovery event)
+ {
+ LOG.info("addScope()");
+ // Add our scope
+ event.addScope(WebSocketScope.class,true,false);
+ }
+
+ public void registerContext(@Observes final AfterBeanDiscovery event)
+ {
+ LOG.info("registerContext()");
+ // Register our context
+ event.addContext(new WebSocketScopeContextImpl());
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000000..aeeef5387c
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,4 @@
+<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+
+</beans> \ No newline at end of file
diff --git a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
new file mode 100644
index 0000000000..a43db084c5
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -0,0 +1 @@
+org.eclipse.jetty.demo.ws.WebSocketScopeExtension \ No newline at end of file
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java
new file mode 100644
index 0000000000..e6039c0c3a
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java
@@ -0,0 +1,99 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.toolchain.test.EventQueue;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+import org.eclipse.jetty.websocket.api.annotations.WebSocket;
+
+@WebSocket
+public class CheckSocket extends WebSocketAdapter
+{
+ private static final Logger LOG = Log.getLogger(CheckSocket.class);
+ private CountDownLatch closeLatch = new CountDownLatch(1);
+ private CountDownLatch openLatch = new CountDownLatch(1);
+ private EventQueue<String> textMessages = new EventQueue<>();
+
+ public void awaitClose(int timeout, TimeUnit timeunit) throws InterruptedException
+ {
+ assertTrue("Timeout waiting for close",closeLatch.await(timeout,timeunit));
+ }
+
+ public void awaitOpen(int timeout, TimeUnit timeunit) throws InterruptedException
+ {
+ assertTrue("Timeout waiting for open",openLatch.await(timeout,timeunit));
+ }
+
+ public EventQueue<String> getTextMessages()
+ {
+ return textMessages;
+ }
+
+ @Override
+ public void onWebSocketClose(int statusCode, String reason)
+ {
+ LOG.debug("Close: {}, {}",statusCode,reason);
+ super.onWebSocketClose(statusCode,reason);
+ closeLatch.countDown();
+ }
+
+ @Override
+ public void onWebSocketConnect(Session sess)
+ {
+ LOG.debug("Open: {}",sess);
+ super.onWebSocketConnect(sess);
+ openLatch.countDown();
+ }
+
+ @Override
+ public void onWebSocketError(Throwable cause)
+ {
+ LOG.warn("WebSocket Error",cause);
+ super.onWebSocketError(cause);
+ }
+
+ @Override
+ public void onWebSocketText(String message)
+ {
+ LOG.debug("TEXT: {}",message);
+ textMessages.add(message);
+ }
+
+ public void sendText(String msg) throws IOException
+ {
+ if (isConnected())
+ {
+ getRemote().sendString(msg);
+ }
+ }
+
+ public void close(int statusCode, String reason)
+ {
+ getSession().close(statusCode,reason);
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java
new file mode 100644
index 0000000000..e531f2aefa
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java
@@ -0,0 +1,129 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.basicapp;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import javax.websocket.server.ServerContainer;
+
+import org.eclipse.jetty.cdi.servlet.EmbeddedCdiHandler;
+import org.eclipse.jetty.cdi.websocket.CheckSocket;
+import org.eclipse.jetty.cdi.websocket.cdiapp.InfoSocket;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.log.JettyLogHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.websocket.api.StatusCode;
+import org.eclipse.jetty.websocket.client.WebSocketClient;
+import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class BasicAppTest
+{
+ private static final Logger LOG = Log.getLogger(BasicAppTest.class);
+
+ private static Server server;
+ private static URI serverHttpURI;
+ private static URI serverWebsocketURI;
+
+ @BeforeClass
+ public static void startServer() throws Exception
+ {
+ JettyLogHandler.config();
+
+ server = new Server();
+ ServerConnector connector = new ServerConnector(server);
+ connector.setPort(0);
+ server.addConnector(connector);
+
+ EmbeddedCdiHandler context = new EmbeddedCdiHandler();
+
+ File baseDir = MavenTestingUtils.getTestResourcesDir();
+
+ context.setBaseResource(Resource.newResource(baseDir));
+ context.setContextPath("/");
+ server.setHandler(context);
+
+ // Add some websockets
+ ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
+ container.addEndpoint(EchoSocket.class);
+ container.addEndpoint(InfoSocket.class);
+
+ server.start();
+
+ String host = connector.getHost();
+ if (host == null)
+ {
+ host = "localhost";
+ }
+ int port = connector.getLocalPort();
+ serverHttpURI = new URI(String.format("http://%s:%d/",host,port));
+ serverWebsocketURI = new URI(String.format("ws://%s:%d/",host,port));
+ }
+
+ @AfterClass
+ public static void stopServer()
+ {
+ try
+ {
+ server.stop();
+ }
+ catch (Exception e)
+ {
+ LOG.warn(e);
+ }
+ }
+
+ @Test
+ public void testWebSocketEcho() throws Exception
+ {
+ WebSocketClient client = new WebSocketClient();
+ try
+ {
+ client.start();
+ CheckSocket socket = new CheckSocket();
+ client.connect(socket,serverWebsocketURI.resolve("/echo"));
+
+ socket.awaitOpen(2,TimeUnit.SECONDS);
+ socket.sendText("Hello World");
+ socket.close(StatusCode.NORMAL,"Test complete");
+ socket.awaitClose(2,TimeUnit.SECONDS);
+
+ assertThat("Messages received",socket.getTextMessages().size(),is(1));
+ String response = socket.getTextMessages().poll();
+ System.err.println(response);
+
+ assertThat("Message[0]",response,is("Hello World"));
+ }
+ finally
+ {
+ client.stop();
+ }
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java
new file mode 100644
index 0000000000..5f0267f027
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java
@@ -0,0 +1,57 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.basicapp;
+
+import javax.websocket.CloseReason;
+import javax.websocket.OnClose;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+@ServerEndpoint("/echo")
+public class EchoSocket
+{
+ private static final Logger LOG = Log.getLogger(EchoSocket.class);
+ @SuppressWarnings("unused")
+ private Session session;
+
+ @OnOpen
+ public void onOpen(Session session)
+ {
+ LOG.debug("onOpen(): {}",session);
+ this.session = session;
+ }
+
+ @OnClose
+ public void onClose(CloseReason close)
+ {
+ LOG.debug("onClose(): {}",close);
+ this.session = null;
+ }
+
+ @OnMessage
+ public String onMessage(String msg)
+ {
+ return msg;
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java
new file mode 100644
index 0000000000..26c89d1140
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java
@@ -0,0 +1,153 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.cdiapp;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import javax.websocket.server.ServerContainer;
+
+import org.eclipse.jetty.cdi.servlet.EmbeddedCdiHandler;
+import org.eclipse.jetty.cdi.websocket.CheckSocket;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.log.JettyLogHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.websocket.api.StatusCode;
+import org.eclipse.jetty.websocket.client.WebSocketClient;
+import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class CdiAppTest
+{
+ private static final Logger LOG = Log.getLogger(CdiAppTest.class);
+ private static Server server;
+ private static URI serverWebsocketURI;
+
+ @BeforeClass
+ public static void startServer() throws Exception
+ {
+ JettyLogHandler.config();
+
+ server = new Server();
+ ServerConnector connector = new ServerConnector(server);
+ connector.setPort(0);
+ server.addConnector(connector);
+
+ EmbeddedCdiHandler context = new EmbeddedCdiHandler();
+
+ File baseDir = MavenTestingUtils.getTestResourcesDir();
+
+ context.setBaseResource(Resource.newResource(baseDir));
+ context.setContextPath("/");
+ server.setHandler(context);
+
+ // Add some websockets
+ ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
+ container.addEndpoint(InfoSocket.class);
+
+ server.start();
+
+ String host = connector.getHost();
+ if (host == null)
+ {
+ host = "localhost";
+ }
+ int port = connector.getLocalPort();
+ serverWebsocketURI = new URI(String.format("ws://%s:%d/",host,port));
+ }
+
+ @AfterClass
+ public static void stopServer()
+ {
+ try
+ {
+ server.stop();
+ }
+ catch (Exception e)
+ {
+ LOG.warn(e);
+ }
+ }
+
+ @Test
+ public void testWebSocketActivated() throws Exception
+ {
+ WebSocketClient client = new WebSocketClient();
+ try
+ {
+ client.start();
+ CheckSocket socket = new CheckSocket();
+ client.connect(socket,serverWebsocketURI.resolve("/echo"));
+
+ socket.awaitOpen(2,TimeUnit.SECONDS);
+ socket.sendText("Hello");
+ socket.close(StatusCode.NORMAL,"Test complete");
+ socket.awaitClose(2,TimeUnit.SECONDS);
+
+ assertThat("Messages received",socket.getTextMessages().size(),is(1));
+ assertThat("Message[0]",socket.getTextMessages().poll(),is("Hello"));
+ }
+ finally
+ {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testWebSocketInfo() throws Exception
+ {
+ WebSocketClient client = new WebSocketClient();
+ try
+ {
+ client.start();
+ CheckSocket socket = new CheckSocket();
+ client.connect(socket,serverWebsocketURI.resolve("/cdi-info"));
+
+ socket.awaitOpen(2,TimeUnit.SECONDS);
+ socket.sendText("info");
+ socket.close(StatusCode.NORMAL,"Test complete");
+ socket.awaitClose(2,TimeUnit.SECONDS);
+
+ assertThat("Messages received",socket.getTextMessages().size(),is(1));
+ String response = socket.getTextMessages().poll();
+ System.err.println(response);
+
+ assertThat("Message[0]",response,
+ allOf(
+ containsString("websocketSession is PRESENT"),
+ containsString("httpSession is PRESENT"),
+ containsString("servletContext is PRESENT")
+ ));
+ }
+ finally
+ {
+ client.stop();
+ }
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/DataMaker.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/DataMaker.java
new file mode 100644
index 0000000000..0d6cbcc8de
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/DataMaker.java
@@ -0,0 +1,34 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.cdiapp;
+
+import javax.inject.Inject;
+
+import org.eclipse.jetty.websocket.api.Session;
+
+public class DataMaker
+{
+ @Inject
+ private Session session;
+
+ public void processMessage(String msg)
+ {
+ session.getRemote().sendStringByFuture("Hello there " + msg);
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java
new file mode 100644
index 0000000000..31cf6cb44c
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java
@@ -0,0 +1,92 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.cdiapp;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.logging.Level;
+
+import javax.enterprise.context.SessionScoped;
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.websocket.CloseReason;
+import javax.websocket.OnClose;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint("/cdi-info")
+public class InfoSocket
+{
+ private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(InfoSocket.class.getName());
+
+ @SessionScoped
+ @Inject
+ private HttpSession httpSession;
+
+ @Inject
+ private ServletContext servletContext;
+
+ @Inject
+ private DataMaker dataMaker;
+
+ private Session session;
+
+ @OnOpen
+ public void onOpen(Session session)
+ {
+ LOG.log(Level.INFO,"onOpen(): {0}",session);
+ this.session = session;
+ }
+
+ @OnClose
+ public void onClose(CloseReason close)
+ {
+ LOG.log(Level.INFO,"onClose(): {}",close);
+ this.session = null;
+ }
+
+ @OnMessage
+ public String onMessage(String msg)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+
+ switch (msg)
+ {
+ case "info":
+ out.printf("websocketSession is %s%n",asPresent(session));
+ out.printf("httpSession is %s%n",asPresent(httpSession));
+ out.printf("servletContext is %s%n",asPresent(servletContext));
+ break;
+ case "data":
+ dataMaker.processMessage(msg);
+ break;
+ }
+
+ return str.toString();
+ }
+
+ private String asPresent(Object obj)
+ {
+ return obj == null ? "NULL" : "PRESENT";
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/BogusSession.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/BogusSession.java
new file mode 100644
index 0000000000..6ea3eb62d9
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/BogusSession.java
@@ -0,0 +1,144 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.scope;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import org.eclipse.jetty.websocket.api.CloseStatus;
+import org.eclipse.jetty.websocket.api.RemoteEndpoint;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.SuspendToken;
+import org.eclipse.jetty.websocket.api.UpgradeRequest;
+import org.eclipse.jetty.websocket.api.UpgradeResponse;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+
+/**
+ * A bogus websocket Session concept object.
+ * <p>
+ * Used to test the scope @Inject of this kind of Session. This is important to test, as the BogusSession does not have
+ * a default constructor that CDI itself can use to create this object.
+ * <p>
+ * This object would need to be added to the beanstore for this scope for later @Inject to use.
+ */
+public class BogusSession implements Session
+{
+ private final String id;
+
+ public BogusSession(String id)
+ {
+ this.id = id;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ @Override
+ public void close()
+ {
+ }
+
+ @Override
+ public void close(CloseStatus closeStatus)
+ {
+ }
+
+ @Override
+ public void close(int statusCode, String reason)
+ {
+ }
+
+ @Override
+ public void disconnect() throws IOException
+ {
+ }
+
+ @Override
+ public long getIdleTimeout()
+ {
+ return 0;
+ }
+
+ @Override
+ public InetSocketAddress getLocalAddress()
+ {
+ return null;
+ }
+
+ @Override
+ public WebSocketPolicy getPolicy()
+ {
+ return null;
+ }
+
+ @Override
+ public String getProtocolVersion()
+ {
+ return null;
+ }
+
+ @Override
+ public RemoteEndpoint getRemote()
+ {
+ return null;
+ }
+
+ @Override
+ public InetSocketAddress getRemoteAddress()
+ {
+ return null;
+ }
+
+ @Override
+ public UpgradeRequest getUpgradeRequest()
+ {
+ return null;
+ }
+
+ @Override
+ public UpgradeResponse getUpgradeResponse()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isOpen()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isSecure()
+ {
+ return false;
+ }
+
+ @Override
+ public void setIdleTimeout(long ms)
+ {
+ }
+
+ @Override
+ public SuspendToken suspend()
+ {
+ return null;
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/BogusSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/BogusSocket.java
new file mode 100644
index 0000000000..864338a8b6
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/BogusSocket.java
@@ -0,0 +1,36 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.scope;
+
+import javax.inject.Inject;
+
+import org.eclipse.jetty.cdi.websocket.WebSocketScope;
+import org.eclipse.jetty.websocket.api.Session;
+
+public class BogusSocket
+{
+ @WebSocketScope
+ @Inject
+ private Session session;
+
+ public Session getSession()
+ {
+ return session;
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/Food.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/Food.java
new file mode 100644
index 0000000000..4df164d1df
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/Food.java
@@ -0,0 +1,64 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.scope;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.eclipse.jetty.cdi.websocket.WebSocketScope;
+
+@WebSocketScope
+public class Food
+{
+ private boolean constructed = false;
+ private boolean destroyed = false;
+ private String name;
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public boolean isConstructed()
+ {
+ return constructed;
+ }
+
+ public boolean isDestroyed()
+ {
+ return destroyed;
+ }
+
+ @PostConstruct
+ void init()
+ {
+ constructed = true;
+ }
+
+ @PreDestroy
+ void destroy()
+ {
+ destroyed = true;
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/Meal.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/Meal.java
new file mode 100644
index 0000000000..2f3f4a58bc
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/Meal.java
@@ -0,0 +1,40 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.scope;
+
+import javax.inject.Inject;
+
+public class Meal
+{
+ @Inject
+ private Food entree;
+
+ @Inject
+ private Food side;
+
+ public Food getEntree()
+ {
+ return entree;
+ }
+
+ public Food getSide()
+ {
+ return side;
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/WebSocketScopeBaselineTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/WebSocketScopeBaselineTest.java
new file mode 100644
index 0000000000..efb6e246d6
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/WebSocketScopeBaselineTest.java
@@ -0,0 +1,116 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.scope;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.Set;
+
+import javax.enterprise.inject.spi.Bean;
+
+import org.eclipse.jetty.cdi.core.AnyLiteral;
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+import org.eclipse.jetty.cdi.core.logging.Logging;
+import org.eclipse.jetty.cdi.websocket.WebSocketScopeContext;
+import org.jboss.weld.environment.se.Weld;
+import org.jboss.weld.environment.se.WeldContainer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class WebSocketScopeBaselineTest
+{
+ private static Weld weld;
+ private static WeldContainer container;
+
+ @BeforeClass
+ public static void startWeld()
+ {
+ Logging.config();
+ weld = new Weld();
+ container = weld.initialize();
+ }
+
+ @AfterClass
+ public static void stopWeld()
+ {
+ weld.shutdown();
+ }
+
+ @Test
+ public void testScopeBehavior() throws Exception
+ {
+ ScopedInstance<WebSocketScopeContext> wsScopeBean = newInstance(WebSocketScopeContext.class);
+ WebSocketScopeContext wsScope = wsScopeBean.instance;
+
+ wsScope.create();
+ Meal meal1;
+ try
+ {
+ wsScope.begin();
+ ScopedInstance<Meal> meal1Bean = newInstance(Meal.class);
+ meal1 = meal1Bean.instance;
+ ScopedInstance<Meal> meal2Bean = newInstance(Meal.class);
+ Meal meal2 = meal2Bean.instance;
+ assertThat("Meals are not the same",meal1,not(sameInstance(meal2)));
+
+ assertThat("Meal 1 Entree Constructed",meal1.getEntree().isConstructed(),is(true));
+ assertThat("Meal 1 Side Constructed",meal1.getSide().isConstructed(),is(true));
+
+ assertThat("Meal parts not the same",meal1.getEntree(),not(sameInstance(meal1.getSide())));
+
+ assertThat("Meal entrees are the same",meal1.getEntree(),sameInstance(meal2.getEntree()));
+ assertThat("Meal sides are the same",meal1.getSide(),sameInstance(meal2.getSide()));
+
+ meal1Bean.destroy();
+ meal2Bean.destroy();
+ }
+ finally
+ {
+ wsScope.end();
+ }
+
+ assertThat("Meal 1 entree destroyed",meal1.getEntree().isDestroyed(),is(false));
+ assertThat("Meal 1 side destroyed",meal1.getSide().isDestroyed(),is(false));
+ wsScope.destroy();
+
+ assertThat("Meal 1 entree destroyed",meal1.getEntree().isDestroyed(),is(true));
+ assertThat("Meal 1 side destroyed",meal1.getSide().isDestroyed(),is(true));
+ wsScopeBean.destroy();
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public static <T> ScopedInstance<T> newInstance(Class<T> clazz) throws Exception
+ {
+ ScopedInstance sbean = new ScopedInstance();
+ Set<Bean<?>> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE);
+ if (beans.size() > 0)
+ {
+ sbean.bean = beans.iterator().next();
+ sbean.creationalContext = container.getBeanManager().createCreationalContext(sbean.bean);
+ sbean.instance = container.getBeanManager().getReference(sbean.bean,clazz,sbean.creationalContext);
+ return sbean;
+ }
+ else
+ {
+ throw new Exception(String.format("Can't find class %s",clazz));
+ }
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/WebSocketScopeSessionTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/WebSocketScopeSessionTest.java
new file mode 100644
index 0000000000..4676127785
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/scope/WebSocketScopeSessionTest.java
@@ -0,0 +1,251 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.cdi.websocket.scope;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import javax.enterprise.inject.spi.Bean;
+
+import org.eclipse.jetty.cdi.core.AnyLiteral;
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+import org.eclipse.jetty.cdi.core.logging.Logging;
+import org.eclipse.jetty.cdi.websocket.WebSocketScopeContext;
+import org.eclipse.jetty.websocket.api.Session;
+import org.jboss.weld.environment.se.Weld;
+import org.jboss.weld.environment.se.WeldContainer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class WebSocketScopeSessionTest
+{
+ private static Weld weld;
+ private static WeldContainer container;
+
+ @BeforeClass
+ public static void startWeld()
+ {
+ Logging.config();
+ weld = new Weld();
+ container = weld.initialize();
+ }
+
+ @AfterClass
+ public static void stopWeld()
+ {
+ weld.shutdown();
+ }
+
+ @Test
+ public void testSessionActivation() throws Exception
+ {
+ ScopedInstance<WebSocketScopeContext> wsScopeBean = newInstance(WebSocketScopeContext.class);
+ WebSocketScopeContext wsScope = wsScopeBean.instance;
+
+ wsScope.create();
+ try
+ {
+ // Scope 1
+ wsScope.begin();
+ BogusSession sess = new BogusSession("1");
+ wsScope.setSession(sess);
+ ScopedInstance<BogusSocket> sock1Bean = newInstance(BogusSocket.class);
+ BogusSocket sock1 = sock1Bean.instance;
+ assertThat("Socket 1 Session",sock1.getSession(),sameInstance((Session)sess));
+
+ sock1Bean.destroy();
+ }
+ finally
+ {
+ wsScope.end();
+ }
+
+ wsScope.destroy();
+ wsScopeBean.destroy();
+ }
+
+ @Test
+ public void testMultiSession_Sequential() throws Exception
+ {
+ ScopedInstance<WebSocketScopeContext> wsScope1Bean = newInstance(WebSocketScopeContext.class);
+ WebSocketScopeContext wsScope1 = wsScope1Bean.instance;
+
+ ScopedInstance<WebSocketScopeContext> wsScope2Bean = newInstance(WebSocketScopeContext.class);
+ WebSocketScopeContext wsScope2 = wsScope2Bean.instance;
+
+ wsScope1.create();
+ try
+ {
+ // Scope 1
+ wsScope1.begin();
+ BogusSession sess = new BogusSession("1");
+ wsScope1.setSession(sess);
+ ScopedInstance<BogusSocket> sock1Bean = newInstance(BogusSocket.class);
+ BogusSocket sock1 = sock1Bean.instance;
+ assertThat("Socket 1 Session",sock1.getSession(),sameInstance((Session)sess));
+ sock1Bean.destroy();
+ }
+ finally
+ {
+ wsScope1.end();
+ }
+
+ wsScope1.destroy();
+ wsScope1Bean.destroy();
+
+ wsScope2.create();
+ try
+ {
+ // Scope 2
+ wsScope2.begin();
+ BogusSession sess = new BogusSession("2");
+ wsScope2.setSession(sess);
+ ScopedInstance<BogusSocket> sock2Bean = newInstance(BogusSocket.class);
+ BogusSocket sock2 = sock2Bean.instance;
+ assertThat("Socket 2 Session",sock2.getSession(),sameInstance((Session)sess));
+ sock2Bean.destroy();
+ }
+ finally
+ {
+ wsScope2.end();
+ }
+
+ wsScope2.destroy();
+ wsScope2Bean.destroy();
+ }
+
+ @Test
+ public void testMultiSession_Overlapping() throws Exception
+ {
+ final CountDownLatch midLatch = new CountDownLatch(2);
+ final CountDownLatch end1Latch = new CountDownLatch(1);
+
+ Callable<Session> call1 = new Callable<Session>() {
+ @Override
+ public Session call() throws Exception
+ {
+ Session ret = null;
+ ScopedInstance<WebSocketScopeContext> wsScope1Bean = newInstance(WebSocketScopeContext.class);
+ WebSocketScopeContext wsScope1 = wsScope1Bean.instance;
+
+ wsScope1.create();
+ try
+ {
+ // Scope 1
+ wsScope1.begin();
+ BogusSession sess = new BogusSession("1");
+ wsScope1.setSession(sess);
+
+ midLatch.countDown();
+ midLatch.await(1, TimeUnit.SECONDS);
+
+ ScopedInstance<BogusSocket> sock1Bean = newInstance(BogusSocket.class);
+ BogusSocket sock1 = sock1Bean.instance;
+ assertThat("Socket 1 Session",sock1.getSession(),sameInstance((Session)sess));
+ ret = sock1.getSession();
+ sock1Bean.destroy();
+ }
+ finally
+ {
+ wsScope1.end();
+ }
+
+ wsScope1.destroy();
+ wsScope1Bean.destroy();
+ end1Latch.countDown();
+ return ret;
+ }
+ };
+
+ final CountDownLatch end2Latch = new CountDownLatch(1);
+
+ Callable<Session> call2 = new Callable<Session>() {
+ @Override
+ public Session call() throws Exception
+ {
+ Session ret = null;
+ ScopedInstance<WebSocketScopeContext> wsScope2Bean = newInstance(WebSocketScopeContext.class);
+ WebSocketScopeContext wsScope2 = wsScope2Bean.instance;
+
+ wsScope2.create();
+ try
+ {
+ // Scope 2
+ wsScope2.begin();
+ BogusSession sess = new BogusSession("2");
+ wsScope2.setSession(sess);
+ ScopedInstance<BogusSocket> sock2Bean = newInstance(BogusSocket.class);
+
+ midLatch.countDown();
+ midLatch.await(1, TimeUnit.SECONDS);
+
+ BogusSocket sock2 = sock2Bean.instance;
+ ret = sock2.getSession();
+ assertThat("Socket 2 Session",sock2.getSession(),sameInstance((Session)sess));
+ sock2Bean.destroy();
+ }
+ finally
+ {
+ wsScope2.end();
+ }
+
+ wsScope2.destroy();
+ wsScope2Bean.destroy();
+ end2Latch.countDown();
+ return ret;
+ }
+ };
+
+ ExecutorService svc = Executors.newFixedThreadPool(4);
+ Future<Session> fut1 = svc.submit(call1);
+ Future<Session> fut2 = svc.submit(call2);
+
+ Session sess1 = fut1.get(1,TimeUnit.SECONDS);
+ Session sess2 = fut2.get(1,TimeUnit.SECONDS);
+
+ assertThat("Sessions are different", sess1, not(sameInstance(sess2)));
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public static <T> ScopedInstance<T> newInstance(Class<T> clazz)
+ {
+ ScopedInstance sbean = new ScopedInstance();
+ Set<Bean<?>> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE);
+ if (beans.size() > 0)
+ {
+ sbean.bean = beans.iterator().next();
+ sbean.creationalContext = container.getBeanManager().createCreationalContext(sbean.bean);
+ sbean.instance = container.getBeanManager().getReference(sbean.bean,clazz,sbean.creationalContext);
+ return sbean;
+ }
+ else
+ {
+ throw new RuntimeException(String.format("Can't find class %s",clazz));
+ }
+ }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml b/jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml
new file mode 100644
index 0000000000..f158a71b6e
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+ http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
+ bean-discovery-mode="all">
+</beans> \ No newline at end of file
diff --git a/jetty-cdi/cdi-websocket/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/jetty-cdi/cdi-websocket/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension
new file mode 100644
index 0000000000..93723bc0ae
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -0,0 +1 @@
+org.eclipse.jetty.cdi.websocket.WebSocketScopeExtension \ No newline at end of file
diff --git a/jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties b/jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000000..f69b351e50
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties
@@ -0,0 +1,11 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.jboss.LEVEL=DEBUG
+org.eclipse.jetty.LEVEL=INFO
+
+org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
+org.eclipse.jetty.cdi.LEVEL=DEBUG
+
+# org.eclipse.jetty.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.client.LEVEL=DEBUG
+
diff --git a/jetty-cdi/cdi-websocket/src/test/resources/logging.properties b/jetty-cdi/cdi-websocket/src/test/resources/logging.properties
new file mode 100644
index 0000000000..cfec8c7ab5
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/resources/logging.properties
@@ -0,0 +1,2 @@
+handlers = org.eclipse.jetty.util.log.JettyLogHandler
+.level=FINE
diff --git a/jetty-cdi/pom.xml b/jetty-cdi/pom.xml
index 154cf43322..da858ba064 100644
--- a/jetty-cdi/pom.xml
+++ b/jetty-cdi/pom.xml
@@ -5,74 +5,18 @@
<version>9.3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
- <artifactId>jetty-cdi</artifactId>
- <name>Jetty :: CDI Configurations</name>
+ <groupId>org.eclipse.jetty.cdi</groupId>
+ <artifactId>jetty-cdi-parent</artifactId>
+ <name>Jetty :: CDI :: Parent</name>
<url>http://www.eclipse.org/jetty</url>
- <packaging>jar</packaging>
+ <packaging>pom</packaging>
<properties>
- <bundle-symbolic-name>${project.groupId}.${project.artifactId}</bundle-symbolic-name>
<weld.version>2.2.9.Final</weld.version>
</properties>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptorRefs>
- <descriptorRef>config</descriptorRef>
- </descriptorRefs>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-plus</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-deploy</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.eclipse.jetty.websocket</groupId>
- <artifactId>websocket-server</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.jboss.weld.servlet</groupId>
- <artifactId>weld-servlet</artifactId>
- <version>${weld.version}</version>
- </dependency>
- <!-- below here lie testing dragons -->
- <dependency>
- <groupId>org.eclipse.jetty.websocket</groupId>
- <artifactId>javax-websocket-server-impl</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>apache-jsp</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.jetty.toolchain</groupId>
- <artifactId>jetty-test-helper</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
+ <modules>
+ <module>cdi-core</module>
+ <module>cdi-servlet</module>
+ <module>cdi-websocket</module>
+ </modules>
</project>
diff --git a/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/JettyWeldInitializer.java b/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/JettyWeldInitializer.java
index 3aea5bf8e6..30faf67aa1 100644
--- a/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/JettyWeldInitializer.java
+++ b/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/JettyWeldInitializer.java
@@ -21,6 +21,7 @@ package org.eclipse.jetty.cdi;
import javax.naming.NamingException;
import javax.naming.Reference;
+import org.eclipse.jetty.cdi.websocket.WebSocketServerLifecycleListener;
import org.eclipse.jetty.plus.jndi.Resource;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.webapp.WebAppContext;
@@ -57,6 +58,8 @@ public class JettyWeldInitializer
public static void initContext(ContextHandler handler) throws NamingException
{
+ handler.addLifeCycleListener(new WebSocketServerLifecycleListener(handler));
+
// Add context specific weld container reference.
// See https://issues.jboss.org/browse/WELD-1710
// and https://github.com/weld/core/blob/2.2.5.Final/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/WeldServletLifecycle.java#L244-L253
@@ -65,8 +68,5 @@ public class JettyWeldInitializer
// Setup Weld BeanManager reference
Reference ref = new Reference("javax.enterprise.inject.spi.BeanManager","org.jboss.weld.resources.ManagerObjectFactory",null);
new Resource(handler,"BeanManager",ref);
-
- // Add just in time listeners for WebSocketServerFactory
- handler.setAttribute("org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope.Listener","org.eclipse.jetty.cdi.weld.WeldScopeInitializer");
}
}
diff --git a/jetty-cdi/src/test/java/org/eclipse/jetty/cdi/weld/cdiapp/CdiInfoSocket.java b/jetty-cdi/src/test/java/org/eclipse/jetty/cdi/weld/cdiapp/CdiInfoSocket.java
index efb50fbf6e..613f4d1a34 100644
--- a/jetty-cdi/src/test/java/org/eclipse/jetty/cdi/weld/cdiapp/CdiInfoSocket.java
+++ b/jetty-cdi/src/test/java/org/eclipse/jetty/cdi/weld/cdiapp/CdiInfoSocket.java
@@ -22,7 +22,7 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Level;
-import javax.enterprise.context.RequestScoped;
+import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
@@ -38,12 +38,15 @@ public class CdiInfoSocket
{
private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CdiInfoSocket.class.getName());
- @RequestScoped
+ @SessionScoped
@Inject
private HttpSession httpSession;
@Inject
private ServletContext servletContext;
+
+ @Inject
+ private DataMaker dataMaker;
private Session session;
@@ -74,6 +77,9 @@ public class CdiInfoSocket
out.printf("httpSession is %s%n",asPresent(httpSession));
out.printf("servletContext is %s%n",asPresent(servletContext));
break;
+ case "data":
+ dataMaker.processMessage(msg);
+ break;
}
return str.toString();
diff --git a/jetty-cdi/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/jetty-cdi/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension
index 1f8343968e..93723bc0ae 100644
--- a/jetty-cdi/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ b/jetty-cdi/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -1 +1 @@
-org.eclipse.jetty.cdi.EventDebugExtension \ No newline at end of file
+org.eclipse.jetty.cdi.websocket.WebSocketScopeExtension \ No newline at end of file
diff --git a/jetty-cdi/src/test/resources/jetty-logging.properties b/jetty-cdi/src/test/resources/jetty-logging.properties
index 65289d2cff..f69b351e50 100644
--- a/jetty-cdi/src/test/resources/jetty-logging.properties
+++ b/jetty-cdi/src/test/resources/jetty-logging.properties
@@ -3,6 +3,7 @@ org.jboss.LEVEL=DEBUG
org.eclipse.jetty.LEVEL=INFO
org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
+org.eclipse.jetty.cdi.LEVEL=DEBUG
# org.eclipse.jetty.LEVEL=DEBUG
# org.eclipse.jetty.websocket.LEVEL=DEBUG

Back to the top