You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by ay...@apache.org on 2016/04/05 10:38:56 UTC

cxf git commit: add a blueprint version of websocket sample for karaf

Repository: cxf
Updated Branches:
  refs/heads/master 0b9cb3da9 -> 64e7c75d2


add a blueprint version of websocket sample for karaf


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

Branch: refs/heads/master
Commit: 64e7c75d2176a39abfd9de40196e7c6eb02cf127
Parents: 0b9cb3d
Author: Akitoshi Yoshida <ay...@apache.org>
Authored: Tue Apr 5 10:38:42 2016 +0200
Committer: Akitoshi Yoshida <ay...@apache.org>
Committed: Tue Apr 5 10:38:42 2016 +0200

----------------------------------------------------------------------
 .../samples/jax_rs/websocket_osgi/README.txt    |  94 +++++++
 .../samples/jax_rs/websocket_osgi/pom.xml       |  94 +++++++
 .../main/java/demo/jaxrs/server/Customer.java   |  43 +++
 .../java/demo/jaxrs/server/CustomerService.java | 271 +++++++++++++++++++
 .../src/main/java/demo/jaxrs/server/Order.java  |  69 +++++
 .../main/java/demo/jaxrs/server/Product.java    |  43 +++
 .../resources/OSGI-INF/blueprint/context.xml    |  47 ++++
 .../websocket_osgi/src/test/resources/client.js | 234 ++++++++++++++++
 8 files changed, 895 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/64e7c75d/distribution/src/main/release/samples/jax_rs/websocket_osgi/README.txt
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/README.txt b/distribution/src/main/release/samples/jax_rs/websocket_osgi/README.txt
new file mode 100644
index 0000000..60d7705
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/README.txt
@@ -0,0 +1,94 @@
+JAX-RS WebSocket OSGi Blueprint Demo 
+=================
+
+This is an OSGi Blueprint version of JAX-RS WebSocket Demo.
+
+Building and running the demo using maven
+---------------------------------------
+
+From the base directory of this sample (i.e., where this README file is
+located), the maven pom.xml file can be used to build and run the demo. 
+
+
+Using either UNIX or Windows:
+
+  mvn install
+
+This will produce a war file in the target folder.
+
+
+Starting Karaf (refer to http://karaf.apache.org/manual/latest-3.0.x/quick-start.html)
+
+  bin/karaf
+
+
+          __ __                  ____      
+         / //_/____ __________ _/ __/      
+        / ,<  / __ `/ ___/ __ `/ /_        
+       / /| |/ /_/ / /  / /_/ / __/        
+      /_/ |_|\__,_/_/   \__,_/_/         
+  
+    Apache Karaf (3.0.4)
+  
+  Hit '<tab>' for a list of available commands
+  and '[cmd] --help' for help on a specific command.
+  Hit '<ctrl-d>' or type 'system:shutdown' or 'logout' to shutdown Karaf.
+
+
+In order to install CXF's features, you need to add the CXF's features repo using
+
+  feature:repo-add cxf 3.n.m
+
+ where 3.n.m corresponds to a valid CXF version number
+
+Install CXF's cxf-jaxrs and cxf-transports-websocket-server features that installs all the required bundles
+for this demo bundle.
+
+  feature:install cxf-jaxrs cxf-transports-websocket-server
+
+Install this demo bundle (using the appropriate bundle version number)
+
+  install -s mvn:org.apache.cxf.samples/jax_rs_websocket_osgi/3.n.m
+
+And verify the bundles are installed.
+
+karaf@root()> feature:repo-add cxf 3.2.0-SNAPSHOT
+Adding feature url mvn:org.apache.cxf.karaf/apache-cxf/3.2.0-SNAPSHOT/xml/features
+karaf@root()> feature:install cxf-jaxrs cxf-transports-websocket-server
+karaf@root()> list -t 0 | grep CXF
+ 80 | Active   |  40 | 3.2.0.SNAPSHOT   | Apache CXF Core                                                    
+ 81 | Active   |  40 | 3.2.0.SNAPSHOT   | Apache CXF Runtime Management                                      
+100 | Active   |  40 | 3.2.0.SNAPSHOT   | Apache CXF Runtime HTTP Transport                                  
+102 | Active   |  40 | 3.2.0.SNAPSHOT   | Apache CXF JAX-RS Extensions: Providers                            
+103 | Active   |  40 | 3.2.0.SNAPSHOT   | Apache CXF JAX-RS Extensions: Search                               
+104 | Active   |  40 | 3.2.0.SNAPSHOT   | Apache CXF JAX-RS Service Description                              
+105 | Active   |  40 | 3.2.0.SNAPSHOT   | Apache CXF Runtime JAX-RS Frontend                                 
+106 | Active   |  40 | 3.2.0.SNAPSHOT   | Apache CXF JAX-RS Client                                           
+108 | Active   |  40 | 3.2.0.SNAPSHOT   | Apache CXF Runtime WebSocket Transport                             
+karaf@root()> install -s mvn:org.apache.cxf.samples/jax_rs_websocket_osgi
+Bundle ID: 109
+karaf@root()> list
+START LEVEL 100 , List Threshold: 50
+ ID | State  | Lvl | Version        | Name                           
+---------------------------------------------------------------------
+107 | Active |  80 | 2.4.3          | atmosphere-runtime             
+109 | Active |  80 | 3.2.0.SNAPSHOT | JAX-RS WebSocket Blueprint Demo
+karaf@root()>
+
+
+Visit http://localhost:8181/cxf/ to see if this RESTful service is registered.
+
+Using Node.js client to test the service
+--------
+
+Go to samples/jax_rs/websocket_osgi/src/test/resources and at the console
+
+Assuming node (>=v4) and npm are installed, execute the following shell commands.
+
+% npm install atmosphere.js
+% node client.js
+
+This client program supports websocket and sse and allows
+you to choose your preferred protocol.
+
+

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e7c75d/distribution/src/main/release/samples/jax_rs/websocket_osgi/pom.xml
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/pom.xml b/distribution/src/main/release/samples/jax_rs/websocket_osgi/pom.xml
new file mode 100644
index 0000000..e0d1234
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>jax_rs_websocket_osgi</artifactId>
+    <packaging>bundle</packaging>
+    <name>JAX-RS WebSocket Blueprint Demo</name>
+    <description>JAX-RS WebSocket Demo</description>
+
+    <parent>
+        <groupId>org.apache.cxf.samples</groupId>
+        <artifactId>cxf-samples</artifactId>
+        <version>3.2.0-SNAPSHOT</version>
+        <relativePath>../..</relativePath>
+    </parent>
+    <properties>
+        <cxf.version>${project.version}</cxf.version>
+        <!-- TODO remove these local entries after making the referenced dependency managed in parent/pom.xml -->
+        <cxf.atmosphere.version>2.4.3</cxf.atmosphere.version>
+        <cxf.jetty92.version>9.2.15.v20160210</cxf.jetty92.version>
+        <cxf.jetty93.version>9.3.5.v20151012</cxf.jetty93.version>
+        <cxf.jetty.version>${cxf.jetty93.version}</cxf.jetty.version>
+    </properties>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.groupId}.${project.artifactId};blueprint.aries.xml-validation:=false</Bundle-SymbolicName>
+                        <Import-Package>
+                            javax.ws.rs,
+                            javax.ws.rs.core,
+                            org.apache.cxf.jaxrs.provider,
+                            org.osgi.service.blueprint,
+                            *
+                        </Import-Package>
+                        <Export-Package>
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+        <!-- cxt et al -->
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-http</artifactId>
+            <version>3.2.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-websocket</artifactId>
+            <version>3.2.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+            <version>3.2.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>javax.ws.rs-api</artifactId>
+        </dependency>
+
+        <!-- add atmosphere -->
+        <dependency>
+            <groupId>org.atmosphere</groupId>
+            <artifactId>atmosphere-runtime</artifactId>
+            <version>${cxf.atmosphere.version}</version>
+        </dependency>
+                
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e7c75d/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Customer.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Customer.java b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Customer.java
new file mode 100644
index 0000000..44025f0
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Customer.java
@@ -0,0 +1,43 @@
+/**
+ * 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 demo.jaxrs.server;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "Customer")
+public class Customer {
+    private long id;
+    private String name;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e7c75d/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/CustomerService.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/CustomerService.java b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/CustomerService.java
new file mode 100644
index 0000000..f77f8aa
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/CustomerService.java
@@ -0,0 +1,271 @@
+/**
+ * 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 demo.jaxrs.server;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.servlet.http.HttpServletResponse;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+
+import org.apache.cxf.transport.websocket.WebSocketConstants;
+
+@Path("/customerservice/")
+@Produces("text/xml")
+public class CustomerService {
+    private static final int MAX_ERROR_COUNT = 5;
+    private static ExecutorService executor = Executors.newSingleThreadExecutor();
+
+    long currentId = 123;
+    Map<Long, Customer> customers = new HashMap<Long, Customer>();
+    Map<Long, Order> orders = new HashMap<Long, Order>();
+    Map<String, WriterHolder<OutputStream>> monitors = new HashMap<String, WriterHolder<OutputStream>>();
+    Map<String, WriterHolder<HttpServletResponse>> monitors2 = new HashMap<String, WriterHolder<HttpServletResponse>>();
+
+    public CustomerService() {
+        init();
+    }
+
+    @GET
+    @Path("/customers/{id}/")
+    public Customer getCustomer(@PathParam("id") String id) {
+        System.out.println("----invoking getCustomer, Customer id is: " + id);
+        long idNumber = Long.parseLong(id);
+        Customer customer = customers.get(idNumber);
+        if (customer != null) {
+            sendCustomerEvent("retrieved", customer);
+        }
+        return customer;
+    }
+
+    @PUT
+    @Path("/customers/")
+    public Response updateCustomer(Customer customer) {
+        System.out.println("----invoking updateCustomer, Customer name is: " + customer.getName());
+        Customer c = customers.get(customer.getId());
+        Response r;
+        if (c != null) {
+            customers.put(customer.getId(), customer);
+            r = Response.ok().build();
+            sendCustomerEvent("updated", customer);
+        } else {
+            r = Response.notModified().build();
+        }
+
+        return r;
+    }
+
+    @POST
+    @Path("/customers/")
+    public Response addCustomer(Customer customer) {
+        System.out.println("----invoking addCustomer, Customer name is: " + customer.getName());
+        customer.setId(++currentId);
+
+        customers.put(customer.getId(), customer);
+        sendCustomerEvent("added", customer);
+        return Response.ok(customer).build();
+    }
+
+    @DELETE
+    @Path("/customers/{id}/")
+    public Response deleteCustomer(@PathParam("id") String id) {
+        System.out.println("----invoking deleteCustomer, Customer id is: " + id);
+        long idNumber = Long.parseLong(id);
+        Customer c = customers.get(idNumber);
+
+        Response r;
+        if (c != null) {
+            r = Response.ok().build();
+            Customer customer = customers.remove(idNumber);
+            if (customer != null) {
+                sendCustomerEvent("deleted", customer);
+            }
+        } else {
+            r = Response.notModified().build();
+        }
+
+        return r;
+    }
+
+    @Path("/orders/{orderId}/")
+    public Order getOrder(@PathParam("orderId") String orderId) {
+        System.out.println("----invoking getOrder, Order id is: " + orderId);
+        long idNumber = Long.parseLong(orderId);
+        Order c = orders.get(idNumber);
+        return c;
+    }
+
+    @GET
+    @Path("/monitor")
+    @Produces("text/*")
+    public StreamingOutput monitorCustomers(
+            @HeaderParam(WebSocketConstants.DEFAULT_REQUEST_ID_KEY) String reqid) {
+        final String key = reqid == null ? "*" : reqid; 
+        return new StreamingOutput() {
+            public void write(final OutputStream out) throws IOException, WebApplicationException {
+                monitors.put(key, new WriterHolder(out, MAX_ERROR_COUNT));
+                out.write(("Subscribed at " + new java.util.Date()).getBytes());
+            }
+            
+        };
+    }
+
+    @GET
+    @Path("/monitor2")
+    @Produces("text/*")
+    public void monitorCustomers2(
+            final @javax.ws.rs.core.Context HttpServletResponse httpResponse,
+            @HeaderParam(WebSocketConstants.DEFAULT_REQUEST_ID_KEY) String reqid) {
+        final String key = reqid == null ? "*" : reqid; 
+        monitors2.put(key, new WriterHolder(httpResponse, MAX_ERROR_COUNT));
+        try {
+            httpResponse.getOutputStream().write(("Subscribed at " + new java.util.Date()).getBytes());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @GET
+    @Path("/unmonitor/{key}")
+    @Produces("text/*")
+    public String unmonitorCustomers(@PathParam("key") String key) {
+        return (monitors.remove(key) != null ? "Removed: " : "Already removed: ") + key; 
+    }
+
+    @GET
+    @Path("/unmonitor2/{key}")
+    @Produces("text/*")
+    public String unmonitorCustomers2(@PathParam("key") String key) {
+        return (monitors2.remove(key) != null ? "Removed: " : "Already removed: ") + key; 
+    }
+
+    private void sendCustomerEvent(final String msg, final Customer customer) {
+        executor.execute(new Runnable() {
+            public void run() {
+                try {
+                    String t = msg + ": " + customer.getId() + "/" + customer.getName();
+                    for (Iterator<WriterHolder<OutputStream>> it = monitors.values().iterator(); it.hasNext();) {
+                        WriterHolder<OutputStream> wh = it.next();
+                        try {
+                            wh.getValue().write(t.getBytes());
+                            wh.getValue().flush();
+                            wh.reset();
+                        } catch (IOException e) {
+                            System.out.println("----error writing to " + wh.getValue() + " " + wh.get());
+                            if (wh.increment()) {
+                                // the max error count reached; purging the output resource
+                                e.printStackTrace();
+                                try {
+                                    wh.getValue().close();
+                                } catch (IOException e2) {
+                                    // ignore;
+                                }
+                                it.remove();
+                                System.out.println("----purged " + wh.getValue());
+                            }
+                        }
+                    }
+                    for (Iterator<WriterHolder<HttpServletResponse>> it = monitors2.values().iterator(); it.hasNext();) {
+                        WriterHolder<HttpServletResponse> wh = it.next();
+                        try {
+                            wh.getValue().getOutputStream().write(t.getBytes());
+                            wh.getValue().getOutputStream().flush();
+                            wh.reset();
+                        } catch (IOException e) {
+                            System.out.println("----error writing to " + wh.getValue() + " " + wh.get());
+                            if (wh.increment()) {
+                                // the max error count reached; purging the output resource
+                                e.printStackTrace();
+                                try {
+                                    wh.getValue().getOutputStream().close();
+                                } catch (IOException e2) {
+                                    // ignore;
+                                }
+                                it.remove();
+                                System.out.println("----purged " + wh.getValue());
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+
+    }
+    final void init() {
+        Customer c = new Customer();
+        c.setName("John");
+        c.setId(123);
+        customers.put(c.getId(), c);
+        c = new Customer();
+        c.setName("Homer");
+        c.setId(235);
+        customers.put(c.getId(), c);
+        
+        Order o = new Order();
+        o.setDescription("order 223");
+        o.setId(223);
+        orders.put(o.getId(), o);
+    }
+
+    private static class WriterHolder<T> {
+        final private T value;
+        final private int max; 
+        final private AtomicInteger errorCount;
+
+        public WriterHolder(T object, int max) {
+            this.value = object;
+            this.max = max;
+            this.errorCount = new AtomicInteger();
+        }
+
+        public T getValue() {
+            return value;
+        }
+
+        public int get() {
+            return errorCount.get();
+        }
+        public boolean increment() {
+            return max < errorCount.getAndIncrement();
+        }
+
+        public void reset() {
+            errorCount.getAndSet(0);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e7c75d/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Order.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Order.java b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Order.java
new file mode 100644
index 0000000..a06b68b
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Order.java
@@ -0,0 +1,69 @@
+/**
+ * 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 demo.jaxrs.server;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "Order")
+public class Order {
+    private long id;
+    private String description;
+    private Map<Long, Product> products = new HashMap<Long, Product>();
+
+    public Order() {
+        init();
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String d) {
+        this.description = d;
+    }
+
+    @GET
+    @Path("products/{productId}/")
+    public Product getProduct(@PathParam("productId")int productId) {
+        System.out.println("----invoking getProduct with id: " + productId);
+        Product p = products.get(new Long(productId));
+        return p;
+    }
+
+    final void init() {
+        Product p = new Product();
+        p.setId(323);
+        p.setDescription("product 323");
+        products.put(p.getId(), p);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e7c75d/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Product.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Product.java b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Product.java
new file mode 100644
index 0000000..4452ec5
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Product.java
@@ -0,0 +1,43 @@
+/**
+ * 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 demo.jaxrs.server;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "Product")
+public class Product {
+    private long id;
+    private String description;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String d) {
+        this.description = d;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e7c75d/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/resources/OSGI-INF/blueprint/context.xml
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/resources/OSGI-INF/blueprint/context.xml b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/resources/OSGI-INF/blueprint/context.xml
new file mode 100644
index 0000000..9bd1cdf
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/resources/OSGI-INF/blueprint/context.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<!-- START SNIPPET: blueprint -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:cxf="http://cxf.apache.org/blueprint/core"
+       xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
+
+       xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
+                           http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
+                           http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd">
+
+
+    <!-- Application resources -->
+    <bean id="sampleResource" class="demo.jaxrs.server.CustomerService" />
+
+    <cxf:bus>
+        <cxf:features>
+            <cxf:logging />
+        </cxf:features>
+    </cxf:bus>
+
+    <jaxrs:server id="websocketSampleService" address="/websocketSample" transportId="http://cxf.apache.org/transports/websocket">
+        <jaxrs:serviceBeans>
+            <ref component-id="sampleResource" />
+        </jaxrs:serviceBeans>
+    </jaxrs:server>
+
+</blueprint>
+<!-- END SNIPPET: blueprint -->

http://git-wip-us.apache.org/repos/asf/cxf/blob/64e7c75d/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/test/resources/client.js
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/test/resources/client.js b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/test/resources/client.js
new file mode 100644
index 0000000..492d520
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/test/resources/client.js
@@ -0,0 +1,234 @@
+/**
+ * client.js
+ * 
+ * A client program to interact with samples/jax_rs/websocket_osgi service
+ * 
+ * 
+ */
+
+"use strict";
+
+// set the host url and path if the service runs at a different location
+var HOST_URL = 'http://localhost:8181';
+var CONTEXT_PATH = "/cxf/websocketSample"
+
+var reader = require('readline');
+var prompt = reader.createInterface(process.stdin, process.stdout);
+
+var atmosphere = require('atmosphere.js');
+
+var request = { url: HOST_URL + CONTEXT_PATH,
+                transport : 'websocket',
+                trackMessageLength: false,
+                dropHeaders: false,
+                reconnectInterval : 5000};
+var isopen = false;
+
+const TRANSPORT_NAMES = ["websocket", "sse"];
+
+const COMMAND_LIST = 
+    [["add name",       "Add a new consumer and return the customer instance. (e.g., add green)"],
+     ["delete id",      "Delete the customer. (e.g., delete 124)"],
+     ["get id",         "Return the customere. (e.g., get 123)"],
+     ["quit",           "Quit the application."],
+     ["subscribe",      "Subscribe to the customer queries."],
+     ["unsubscribe",    "Unsubscribe from the customer queries."],
+     ["update id name", "Update the customer. (e.g., update 125 red)"]];
+
+function selectOption(c, opts) {
+    var i = parseInt(c);
+    if (!(i >= 0 && i < opts.length)) {
+        console.log('Invalid selection: ' + c + '; Using ' + opts[0]);
+        i = 0;
+    }
+    return opts[i];
+}
+
+function getArgs(name, msg) {
+    var sp = name.length;
+    if (msg.length > name.length && msg.charAt(name.length) != ' ') {
+        // remove the command suffix
+        sp = msg.indexOf(' ', name.length);
+        if (sp < 0) {
+            sp = msg.length;
+        }
+    }
+    return msg.substring(sp).trim().split(' ');
+}
+
+function createAddCustomerPayload(name) {
+    return "<?xml version=\"1.0\"?>\n<Customer>\n    <name>" + name + "</name>\n</Customer>\n";
+}
+
+function createUpdateCustomerPayload(id, name) {
+    return "<?xml version=\"1.0\"?>\n<Customer>\n    <name>" + name + "</name>\n    <id>" + id + "</id>\n</Customer>\n";
+}
+
+///
+
+function doHelp() {
+    console.log('Available commands');
+    for (var i = 0; i < COMMAND_LIST.length; i++) { 
+        var c = COMMAND_LIST[i][0];
+        console.log(c + "                    ".substring(0, 20 - c.length) + COMMAND_LIST[i][1]);
+    }
+}
+
+function doAdd(v) {
+    var req;
+    if (transport == 'websocket') {
+        req = "POST " + CONTEXT_PATH + "/customerservice/customers\r\nContent-Type: text/xml; charset='utf-8'\r\nAccept: text/xml\r\n\r\n" 
+            + createAddCustomerPayload(v[0]);
+    } else if (transport == 'sse') {
+        req = {"method": "POST", "url": HOST_URL + CONTEXT_PATH + "/customerservice/customers", "headers": {"content-type": "text/xml; charset=utf-8", "accept": "text/xml"}, "data": createAddCustomerPayload(v[0])}
+    }
+    console.log("TRACE: sending ", req);
+    subSocket.push(req);
+}
+
+function doDelete(v) {
+    var req;
+    if (transport == 'websocket') {
+        req = "DELETE" + CONTEXT_PATH + "/customerservice/customers/" + v[0];
+    } else if (transport == 'sse') {
+        req = {"method": "DELETE", "url": HOST_URL + CONTEXT_PATH + "/customerservice/customers/" + v[0]}
+    }
+    console.log("TRACE: sending ", req);
+    subSocket.push(req);
+}
+
+function doGet(v) {
+    var req;
+    if (transport == 'websocket') {
+        req = "GET " + CONTEXT_PATH + "/customerservice/customers/" + v[0];
+    } else if (transport == 'sse') {
+        req = {"method": "GET", "url": HOST_URL + CONTEXT_PATH + "/customerservice/customers/" + v[0]}
+    }
+    console.log("TRACE: sending ", req);
+    subSocket.push(req);
+}
+
+function doSubscribe() {
+    var req;
+    if (transport == 'websocket') {
+        req = "GET " + CONTEXT_PATH + "/customerservice/monitor\r\nAccept: text/plain\r\n";
+    } else if (transport == 'sse') {
+        req = {"method": "GET", "url": HOST_URL + CONTEXT_PATH + "/customerservice/monitor", "headers": {"accept": "text/plain"}}
+    }
+    console.log("TRACE: sending ", req);
+    subSocket.push(req);
+}
+
+function doUnsubscribe() {
+    var req;
+    if (transport == 'websocket') {
+        req = "GET " + CONTEXT_PATH + "/customerservice/unmonitor/*\r\nAccept: text/plain\r\n";
+    } else if (transport == 'sse') {
+        req = {"method": "GET", "url": HOST_URL + CONTEXT_PATH + "/customerservice/unmonitor/*", "headers": {"accept": "text/plain"}}
+    }
+    console.log("TRACE: sending ", req);
+    subSocket.push(req);
+}
+
+function doUpdate(v) {
+    var req;
+    if (transport == 'websocket') {
+        req = "PUT " + CONTEXT_PATH + "/customerservice/customers\r\nContent-Type: text/xml; charset='utf-8'\r\nAccept: text/xml\r\n\r\n" 
+            + createUpdateCustomerPayload(v[0], v[1]);
+    } else if (transport == 'sse') {
+        req = {"method": "PUT", "url": HOST_URL + CONTEXT_PATH + "/customerservice/customers", "headers": {"content-type": "text/xml; charset=utf-8", "accept": "text/xml"}, "data": createUpdateCustomerPayload(v[0], v[1])}
+    }
+    console.log("TRACE: sending ", req);
+    subSocket.push(req);
+}
+
+function doQuit() {
+    subSocket.close();
+    process.exit(0);
+}
+
+///
+
+request.onOpen = function(response) {
+    isopen = true;
+    console.log('Connected using ' + response.transport);
+    prompt.setPrompt("> ", 2);
+    prompt.prompt();
+};
+
+request.onMessage = function (response) {
+    var message = response.responseBody;
+    console.log('Received: ', message);
+    console.log('------------------------------------------------------------------------');
+    prompt.setPrompt("> ", 2);
+    prompt.prompt();
+};
+
+request.onReconnect = function(response) {
+    console.log('Reconnecting ...');
+}
+
+request.onReopen = function(response) {
+    isopen = true;
+    console.log('Reconnected using ' + response.transport);
+    prompt.setPrompt("> ", 2);
+    prompt.prompt();
+}
+
+request.onClose = function(response) {
+    isopen = false;
+}
+
+request.onError = function(response) {
+    console.log("Sorry, something went wrong: " + response.responseBody);
+};
+
+var transport = null;
+var subSocket = null;
+var author = null;
+
+console.log("Select transport ...");
+for (var i = 0; i < TRANSPORT_NAMES.length; i++) { 
+    console.log(i + ": " + TRANSPORT_NAMES[i]);
+}
+prompt.setPrompt("select: ", 6);
+prompt.prompt();
+
+prompt.
+on('line', function(line) {
+    var msg = line.trim();
+    if (transport == null) {
+        transport = selectOption(msg, TRANSPORT_NAMES);
+        request.transport = transport;
+        subSocket = atmosphere.subscribe(request);
+        console.log("Connecting using " + transport);
+        setTimeout(function() {
+            if (!isopen) {
+                console.log("Unable to open a connection. Terminated.");
+                process.exit(0);
+            }
+        }, 3000);
+    } else if (msg.length == 0) {
+        doHelp();
+    } else if (msg.indexOf("add") == 0) {
+        doAdd(getArgs("add", msg));
+    } else if (msg.indexOf("del") == 0) {
+        doDelete(getArgs("del", msg));
+    } else if (msg.indexOf("get") == 0) {
+        doGet(getArgs("get", msg));
+    } else if (msg.indexOf("quit") == 0) {
+        doQuit();
+    } else if (msg.indexOf("sub") == 0) {
+        doSubscribe(getArgs("sub", msg));
+    } else if (msg.indexOf("unsub") == 0) {
+        doUnsubscribe(getArgs("unsub", msg));
+    } else if (msg.indexOf("update") == 0) {
+        doUpdate(getArgs("update", msg));
+    }
+    prompt.setPrompt("> ", 2);
+    prompt.prompt();
+}).
+on('close', function() {
+    console.log("close");
+    process.exit(0);
+});