You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2017/02/17 13:59:08 UTC

cxf git commit: Support for the constructor injection into the singleton resources starting from Application.getClasses

Repository: cxf
Updated Branches:
  refs/heads/master 19a4d72a3 -> 64e17b906


Support for the constructor injection into the singleton resources starting from Application.getClasses


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/64e17b90
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/64e17b90
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/64e17b90

Branch: refs/heads/master
Commit: 64e17b90635e7acd6f0836ab2bb8f6ede026ecff
Parents: 19a4d72
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Fri Feb 17 13:58:53 2017 +0000
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Fri Feb 17 13:58:53 2017 +0000

----------------------------------------------------------------------
 .../cxf/cdi/JAXRSCdiResourceExtension.java      |   6 +-
 .../cxf/jaxrs/JAXRSServerFactoryBean.java       |  22 +--
 .../cxf/jaxrs/impl/RuntimeDelegateImpl.java     |   2 +-
 .../lifecycle/SingletonResourceProvider.java    |  36 ++++-
 .../jaxrs/servlet/CXFNonSpringJaxrsServlet.java |  22 ++-
 .../apache/cxf/jaxrs/utils/ResourceUtils.java   |  33 +++--
 .../cxf/jaxrs/model/ClassResourceInfoTest.java  |   2 +-
 .../cxf/jaxrs/utils/ResourceUtilsTest.java      |   6 +-
 .../cxf/systest/jaxrs/sse/BookStore2.java       | 136 +++++++++++++++++++
 .../cxf/systest/jaxrs/sse/SseApplication.java   |  38 ++++++
 .../test/resources/jaxrs_sse/WEB-INF/web.xml    |   8 +-
 11 files changed, 265 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java
----------------------------------------------------------------------
diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java
index 51c4f2f..8ec1781 100644
--- a/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java
+++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java
@@ -187,7 +187,8 @@ public class JAXRSCdiResourceExtension implements Extension {
     private JAXRSServerFactoryBean createFactoryInstance(final Application application, final List< ? > services,
             final List< ? > providers, final List< ? extends Feature > features) {
 
-        final JAXRSServerFactoryBean instance = ResourceUtils.createApplication(application, false, false, bus);
+        final JAXRSServerFactoryBean instance = 
+            ResourceUtils.createApplication(application, false, false, false, bus);
         instance.setServiceBeans(new ArrayList<>(services));
         instance.setProviders(providers);
         instance.setProviders(loadExternalProviders());
@@ -203,7 +204,8 @@ public class JAXRSCdiResourceExtension implements Extension {
      */
     private JAXRSServerFactoryBean createFactoryInstance(final Application application, final BeanManager beanManager) {
 
-        final JAXRSServerFactoryBean instance = ResourceUtils.createApplication(application, false, false, bus);
+        final JAXRSServerFactoryBean instance = 
+            ResourceUtils.createApplication(application, false, false, false, bus);
         final ClassifiedClasses classified = classes2singletons(application, beanManager);
 
         instance.setProviders(classified.getProviders());

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java
index 123642f..3aff010 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java
@@ -44,6 +44,7 @@ import org.apache.cxf.jaxrs.ext.ResourceComparator;
 import org.apache.cxf.jaxrs.impl.RequestPreprocessor;
 import org.apache.cxf.jaxrs.lifecycle.PerRequestResourceProvider;
 import org.apache.cxf.jaxrs.lifecycle.ResourceProvider;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
 import org.apache.cxf.jaxrs.model.ApplicationInfo;
 import org.apache.cxf.jaxrs.model.ClassResourceInfo;
 import org.apache.cxf.jaxrs.provider.ServerProviderFactory;
@@ -159,7 +160,6 @@ public class JAXRSServerFactoryBean extends AbstractJAXRSFactoryBean {
             checkResources(true);
             if (serviceFactory.getService() == null) {
                 serviceFactory.create();
-                updateClassResourceProviders();
             }
 
             Endpoint ep = createEndpoint();
@@ -196,6 +196,7 @@ public class JAXRSServerFactoryBean extends AbstractJAXRSFactoryBean {
             applyBusFeatures(getBus());
             applyFeatures();
 
+            updateClassResourceProviders(ep);
             injectContexts(factory);
             factory.applyDynamicFeatures(getServiceFactory().getClassResourceInfo());
             
@@ -427,17 +428,18 @@ public class JAXRSServerFactoryBean extends AbstractJAXRSFactoryBean {
         }
     }
 
-    protected void updateClassResourceProviders() {
+    protected void updateClassResourceProviders(Endpoint ep) {
         for (ClassResourceInfo cri : serviceFactory.getClassResourceInfo()) {
-            if (cri.getResourceProvider() != null) {
-                continue;
+            if (cri.getResourceProvider() == null) {
+                ResourceProvider rp = resourceProviders.get(cri.getResourceClass());
+                if (rp != null) {
+                    cri.setResourceProvider(rp);
+                } else {
+                    setDefaultResourceProvider(cri);
+                }
             }
-
-            ResourceProvider rp = resourceProviders.get(cri.getResourceClass());
-            if (rp != null) {
-                cri.setResourceProvider(rp);
-            } else {
-                setDefaultResourceProvider(cri);
+            if (cri.getResourceProvider() instanceof SingletonResourceProvider) {
+                ((SingletonResourceProvider)cri.getResourceProvider()).init(ep);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RuntimeDelegateImpl.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RuntimeDelegateImpl.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RuntimeDelegateImpl.java
index 612578c..3dcc399 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RuntimeDelegateImpl.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RuntimeDelegateImpl.java
@@ -110,7 +110,7 @@ public class RuntimeDelegateImpl extends RuntimeDelegate {
             && !JAXRSServerFactoryBean.class.isAssignableFrom(endpointType))) {
             throw new IllegalArgumentException();
         }
-        JAXRSServerFactoryBean bean = ResourceUtils.createApplication(app, false);
+        JAXRSServerFactoryBean bean = ResourceUtils.createApplication(app, false, false, false, null);
         if (JAXRSServerFactoryBean.class.isAssignableFrom(endpointType)) {
             return endpointType.cast(bean);
         }

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/lifecycle/SingletonResourceProvider.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/lifecycle/SingletonResourceProvider.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/lifecycle/SingletonResourceProvider.java
index 519b4fc..a188359 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/lifecycle/SingletonResourceProvider.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/lifecycle/SingletonResourceProvider.java
@@ -19,10 +19,17 @@
 
 package org.apache.cxf.jaxrs.lifecycle;
 
+import java.lang.reflect.Constructor;
+import java.util.Collections;
+
 import org.apache.cxf.common.util.ClassHelper;
+import org.apache.cxf.endpoint.Endpoint;
 import org.apache.cxf.jaxrs.utils.InjectionUtils;
 import org.apache.cxf.jaxrs.utils.ResourceUtils;
+import org.apache.cxf.message.ExchangeImpl;
 import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.cxf.service.factory.ServiceConstructionException;
 
 /**
  * The default singleton resource provider which returns
@@ -30,19 +37,38 @@ import org.apache.cxf.message.Message;
  */
 public class SingletonResourceProvider implements ResourceProvider {
     private Object resourceInstance;
-
+    private boolean callPostConstruct;
+    
     public SingletonResourceProvider(Object o, boolean callPostConstruct) {
         resourceInstance = o;
-        if (callPostConstruct) {
-            InjectionUtils.invokeLifeCycleMethod(o,
-                ResourceUtils.findPostConstructMethod(ClassHelper.getRealClass(o)));
-        }
+        this.callPostConstruct = callPostConstruct;
     }
 
     public SingletonResourceProvider(Object o) {
         this(o, false);
     }
 
+    public void init(Endpoint ep) {
+        if (resourceInstance instanceof Constructor) {
+            Constructor<?> c = (Constructor<?>)resourceInstance;
+            Message m = new MessageImpl();
+            ExchangeImpl exchange = new ExchangeImpl();
+            exchange.put(Endpoint.class, ep);
+            m.setExchange(exchange);
+            Object[] values = 
+                ResourceUtils.createConstructorArguments(c, m, false, Collections.emptyMap());
+            try {
+                resourceInstance = values.length > 0 ? c.newInstance(values) : c.newInstance(new Object[]{});
+            } catch (Exception ex) {
+                throw new ServiceConstructionException(ex);
+            }
+        }
+        if (callPostConstruct) {
+            InjectionUtils.invokeLifeCycleMethod(resourceInstance,
+                ResourceUtils.findPostConstructMethod(ClassHelper.getRealClass(resourceInstance)));
+        }    
+    }
+    
     /**
      * {@inheritDoc}
      */

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/servlet/CXFNonSpringJaxrsServlet.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/servlet/CXFNonSpringJaxrsServlet.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/servlet/CXFNonSpringJaxrsServlet.java
index 1ad1fe9..a90ef65 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/servlet/CXFNonSpringJaxrsServlet.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/servlet/CXFNonSpringJaxrsServlet.java
@@ -415,7 +415,11 @@ public class CXFNonSpringJaxrsServlet extends CXFNonSpringServlet {
         return map;
     }
 
-
+    protected boolean isResourceLifecycleASingleton(ServletConfig servletConfig) {
+        String scope = servletConfig.getInitParameter(SERVICE_SCOPE_PARAM);
+        return SERVICE_SCOPE_SINGLETON.equals(scope);
+    }
+    
     protected Object createSingletonInstance(Class<?> cls, Map<String, List<String>> props, ServletConfig sc)
         throws ServletException {
         Constructor<?> c = ResourceUtils.findResourceConstructor(cls, false);
@@ -500,9 +504,12 @@ public class CXFNonSpringJaxrsServlet extends CXFNonSpringServlet {
         for (String cName : classNames) {
             ApplicationInfo providerApp = createApplicationInfo(cName, servletConfig);
 
-            JAXRSServerFactoryBean bean = ResourceUtils.createApplication(providerApp.getProvider(),
+            JAXRSServerFactoryBean bean = ResourceUtils.createApplication(
+                                                providerApp.getProvider(),
                                                 ignoreApplicationPath,
-                                                getStaticSubResolutionValue(servletConfig));
+                                                getStaticSubResolutionValue(servletConfig),
+                                                isResourceLifecycleASingleton(servletConfig),
+                                                getBus());
             String splitChar = getParameterSplitChar(servletConfig);
             setAllInterceptors(bean, servletConfig, splitChar);
             setInvoker(bean, servletConfig);
@@ -523,9 +530,12 @@ public class CXFNonSpringJaxrsServlet extends CXFNonSpringServlet {
     protected void createServerFromApplication(ServletConfig servletConfig)
         throws ServletException {
 
-        JAXRSServerFactoryBean bean = ResourceUtils.createApplication(getApplication(),
-                                                                      isIgnoreApplicationPath(servletConfig),
-                                                                      getStaticSubResolutionValue(servletConfig));
+        JAXRSServerFactoryBean bean = ResourceUtils.createApplication(
+                                          getApplication(),
+                                          isIgnoreApplicationPath(servletConfig),
+                                          getStaticSubResolutionValue(servletConfig),
+                                          isResourceLifecycleASingleton(servletConfig),
+                                          getBus());
         bean.setBus(getBus());
         bean.setApplication(getApplication());
         bean.create();

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ResourceUtils.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ResourceUtils.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ResourceUtils.java
index 6fffea3..999a492 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ResourceUtils.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ResourceUtils.java
@@ -100,6 +100,7 @@ import org.apache.cxf.jaxrs.model.UserOperation;
 import org.apache.cxf.jaxrs.model.UserResource;
 import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
 import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
 import org.apache.cxf.resource.ResourceManager;
 import org.apache.cxf.staxutils.StaxUtils;
 
@@ -124,7 +125,7 @@ public final class ResourceUtils {
         SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.container.ContainerRequestFilter");
         SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.container.ContainerResponseFilter");
         SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.container.DynamicFeature");
-        SERVER_PROVIDER_CLASS_NAMES.add("org.apache.cxf.jaxrs.ext.ContextResolver");
+        SERVER_PROVIDER_CLASS_NAMES.add("org.apache.cxf.jaxrs.ext.ContextProvider");
 
     }
 
@@ -779,12 +780,15 @@ public final class ResourceUtils {
                                                       Message m,
                                                       boolean perRequest,
                                                       Map<Class<?>, Object> contextValues) {
+        if (m == null) {
+            m = new MessageImpl();
+        }
         Class<?>[] params = c.getParameterTypes();
         Annotation[][] anns = c.getParameterAnnotations();
         Type[] genericTypes = c.getGenericParameterTypes();
         @SuppressWarnings("unchecked")
-        MultivaluedMap<String, String> templateValues = m == null ? null
-            : (MultivaluedMap<String, String>)m.get(URITemplate.TEMPLATE_PARAMETERS);
+        MultivaluedMap<String, String> templateValues = 
+            (MultivaluedMap<String, String>)m.get(URITemplate.TEMPLATE_PARAMETERS);
         Object[] values = new Object[params.length];
         for (int i = 0; i < params.length; i++) {
             if (AnnotationUtils.getAnnotation(anns[i], Context.class) != null) {
@@ -808,18 +812,13 @@ public final class ResourceUtils {
         }
         return values;
     }
-    public static JAXRSServerFactoryBean createApplication(Application app, boolean ignoreAppPath) {
-        return createApplication(app, ignoreAppPath, false);
-    }
-
-    public static JAXRSServerFactoryBean createApplication(Application app, boolean ignoreAppPath,
-            boolean staticSubresourceResolution) {
-        return createApplication(app, ignoreAppPath, staticSubresourceResolution, null);
-    }
-
+    
     @SuppressWarnings("unchecked")
-    public static JAXRSServerFactoryBean createApplication(Application app, boolean ignoreAppPath,
-            boolean staticSubresourceResolution, Bus bus) {
+    public static JAXRSServerFactoryBean createApplication(Application app, 
+                                                           boolean ignoreAppPath,
+                                                           boolean staticSubresourceResolution, 
+                                                           boolean useSingletonResourceProvider,
+                                                           Bus bus) {
 
         Set<Object> singletons = app.getSingletons();
         verifySingletons(singletons);
@@ -839,7 +838,11 @@ public final class ResourceUtils {
                     features.add(createFeatureInstance((Class<? extends Feature>) cls));
                 } else {
                     resourceClasses.add(cls);
-                    map.put(cls, new PerRequestResourceProvider(cls));
+                    if (useSingletonResourceProvider) {
+                        map.put(cls, new SingletonResourceProvider(createProviderInstance(cls)));
+                    } else {
+                        map.put(cls, new PerRequestResourceProvider(cls));
+                    }
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/ClassResourceInfoTest.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/ClassResourceInfoTest.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/ClassResourceInfoTest.java
index 251f7f2..a0b839f 100644
--- a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/ClassResourceInfoTest.java
+++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/ClassResourceInfoTest.java
@@ -249,7 +249,7 @@ public class ClassResourceInfoTest extends Assert {
     @Test
     public void testNameBindings() {
         Application app = new TestApplication();
-        JAXRSServerFactoryBean bean = ResourceUtils.createApplication(app, true, true);
+        JAXRSServerFactoryBean bean = ResourceUtils.createApplication(app, true, true, false, null);
         ClassResourceInfo cri = bean.getServiceFactory().getClassResourceInfo().get(0);
         Set<String> names = cri.getNameBindings();
         assertEquals(Collections.singleton(CustomNameBinding.class.getName()), names);

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/ResourceUtilsTest.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/ResourceUtilsTest.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/ResourceUtilsTest.java
index f4f908e..4edc5bd 100644
--- a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/ResourceUtilsTest.java
+++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/ResourceUtilsTest.java
@@ -164,13 +164,15 @@ public class ResourceUtilsTest extends Assert {
 
     @Test
     public void shouldCreateApplicationWhichInheritsApplicationPath() throws Exception {
-        JAXRSServerFactoryBean application = ResourceUtils.createApplication(new SuperApplication(), false);
+        JAXRSServerFactoryBean application = ResourceUtils.createApplication(
+                                                 new SuperApplication(), false, false, false, null);
         assertEquals("/base", application.getAddress());
     }
 
     @Test
     public void shouldCreateApplicationWhichOverridesApplicationPath() throws Exception {
-        JAXRSServerFactoryBean application = ResourceUtils.createApplication(new CustomApplication(), false);
+        JAXRSServerFactoryBean application = ResourceUtils.createApplication(
+                                                 new CustomApplication(), false, false, false, null);
         assertEquals("/custom", application.getAddress());
     }
 

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java
----------------------------------------------------------------------
diff --git a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java
new file mode 100644
index 0000000..68603f9
--- /dev/null
+++ b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java
@@ -0,0 +1,136 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.jaxrs.sse;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.sse.OutboundSseEvent;
+import javax.ws.rs.sse.OutboundSseEvent.Builder;
+import javax.ws.rs.sse.Sse;
+import javax.ws.rs.sse.SseBroadcaster;
+import javax.ws.rs.sse.SseEventSink;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Path("/api/bookstore")
+public class BookStore2 {
+    private static final Logger LOG = LoggerFactory.getLogger(BookStore2.class);
+
+    private final CountDownLatch latch = new CountDownLatch(2);
+    private Sse sse;
+    private SseBroadcaster broadcaster;
+
+    public BookStore2(@Context Sse sse) {
+        this.sse = sse;
+        this.broadcaster = sse.newBroadcaster();
+    }
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Collection<Book> books() {
+        return Arrays.asList(
+                new Book("New Book #1", 1),
+                new Book("New Book #2", 2)
+            );
+    }
+
+    @GET
+    @Path("sse/{id}")
+    @Produces(MediaType.SERVER_SENT_EVENTS)
+    public void forBook(@Context SseEventSink sink, @PathParam("id") final String id,
+            @HeaderParam(HttpHeaders.LAST_EVENT_ID_HEADER) @DefaultValue("0") final String lastEventId) {
+
+        new Thread() {
+            public void run() {
+                try {
+                    final Integer id = Integer.valueOf(lastEventId);
+                    final Builder builder = sse.newEventBuilder();
+
+                    sink.onNext(createStatsEvent(builder.name("book"), id + 1));
+                    Thread.sleep(200);
+                    sink.onNext(createStatsEvent(builder.name("book"), id + 2));
+                    Thread.sleep(200);
+                    sink.onNext(createStatsEvent(builder.name("book"), id + 3));
+                    Thread.sleep(200);
+                    sink.onNext(createStatsEvent(builder.name("book"), id + 4));
+                    Thread.sleep(200);
+                    sink.close();
+                } catch (final InterruptedException | IOException ex) {
+                    LOG.error("Communication error", ex);
+                }
+            }
+        }.start();
+    }
+
+    @GET
+    @Path("broadcast/sse")
+    @Produces(MediaType.SERVER_SENT_EVENTS)
+    public void broadcast(@Context SseEventSink sink) {
+        try {
+            broadcaster.subscribe(sink);
+        } finally {
+            latch.countDown();
+        }
+    }
+
+    @POST
+    @Path("broadcast/close")
+    public void stop() {
+        try {
+            // Await a least 2 clients to be broadcasted over
+            if (!latch.await(10, TimeUnit.SECONDS)) {
+                LOG.warn("Not enough clients have been connected, closing broadcaster anyway");
+            }
+
+            final Builder builder = sse.newEventBuilder();
+            broadcaster.broadcast(createStatsEvent(builder.name("book"), 1000));
+            broadcaster.broadcast(createStatsEvent(builder.name("book"), 2000));
+
+        } catch (final InterruptedException ex) {
+            LOG.error("Wait has been interrupted", ex);
+        }
+
+        if (broadcaster != null) {
+            broadcaster.close();
+        }
+    }
+
+    private static OutboundSseEvent createStatsEvent(final OutboundSseEvent.Builder builder, final int eventId) {
+        return builder
+            .id(Integer.toString(eventId))
+            .data(Book.class, new Book("New Book #" + eventId, eventId))
+            .mediaType(MediaType.APPLICATION_JSON_TYPE)
+            .build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java
----------------------------------------------------------------------
diff --git a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java
new file mode 100644
index 0000000..a4a4049
--- /dev/null
+++ b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.jaxrs.sse;
+
+import java.util.Collections;
+import java.util.Set;
+
+import javax.ws.rs.core.Application;
+
+import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
+
+public class SseApplication extends Application {
+    @Override
+    public Set<Class<?>> getClasses() {
+        return Collections.singleton(BookStore2.class);
+    }
+
+    @Override
+    public Set<Object> getSingletons() {
+        return Collections.singleton(new JacksonJsonProvider());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e17b90/systests/rs-sse/src/test/resources/jaxrs_sse/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/systests/rs-sse/src/test/resources/jaxrs_sse/WEB-INF/web.xml b/systests/rs-sse/src/test/resources/jaxrs_sse/WEB-INF/web.xml
index d446f8ec..64746acb 100644
--- a/systests/rs-sse/src/test/resources/jaxrs_sse/WEB-INF/web.xml
+++ b/systests/rs-sse/src/test/resources/jaxrs_sse/WEB-INF/web.xml
@@ -12,12 +12,12 @@
 			<param-value>http://cxf.apache.org/transports/http/sse</param-value>
 		</init-param>
 		<init-param>
-			<param-name>jaxrs.serviceClasses</param-name>
-			<param-value>org.apache.cxf.systest.jaxrs.sse.BookStore</param-value>
+			<param-name>javax.ws.rs.Application</param-name>
+			<param-value>org.apache.cxf.systest.jaxrs.sse.SseApplication</param-value>
 		</init-param>
 		<init-param>
-			<param-name>jaxrs.providers</param-name>
-			<param-value>com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider</param-value>
+			<param-name>jaxrs.scope</param-name>
+			<param-value>singleton</param-value>
 		</init-param>
 	</servlet>