cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a.@apache.org
Subject git commit: add a jaxrs websocket browser demo in the sample collection
Date Mon, 24 Mar 2014 09:58:07 GMT
Repository: cxf
Updated Branches:
  refs/heads/master c17955382 -> abe5b35ec


add a jaxrs websocket browser demo in the sample collection


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

Branch: refs/heads/master
Commit: abe5b35ec859a2bae12c44bb4a7a8f1a118c6cf6
Parents: c179553
Author: Akitoshi Yoshida <ay@apache.org>
Authored: Mon Mar 24 10:56:48 2014 +0100
Committer: Akitoshi Yoshida <ay@apache.org>
Committed: Mon Mar 24 10:56:48 2014 +0100

----------------------------------------------------------------------
 .../release/samples/jax_rs/websocket/README.txt | 132 ++++++++
 .../release/samples/jax_rs/websocket/pom.xml    | 145 +++++++++
 .../src/main/java/demo/jaxrs/client/Client.java | 116 ++++++++
 .../demo/jaxrs/client/WebSocketTestClient.java  | 298 +++++++++++++++++++
 .../main/java/demo/jaxrs/server/Customer.java   |  43 +++
 .../java/demo/jaxrs/server/CustomerService.java | 176 +++++++++++
 .../src/main/java/demo/jaxrs/server/Order.java  |  69 +++++
 .../main/java/demo/jaxrs/server/Product.java    |  43 +++
 .../src/main/java/demo/jaxrs/server/Server.java |  45 +++
 .../src/main/resources/add_customer.xml         |   4 +
 .../websocket/src/main/resources/index.html     | 172 +++++++++++
 .../src/main/resources/update_customer.xml      |   5 +
 12 files changed, 1248 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/README.txt
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/README.txt b/distribution/src/main/release/samples/jax_rs/websocket/README.txt
new file mode 100644
index 0000000..19d8ecb
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket/README.txt
@@ -0,0 +1,132 @@
+JAX-RS WebSocket Demo 
+=================
+
+This is a websocket transport version of JAX-RS Basic Demo.
+
+A RESTful customer service is provided on URL ws://localhost:9000/customers. 
+Users access this URI to operate on customer.
+
+Open a websocket to ws://localhost:9000/ and send requests over the websocket.
+
+A GET request to path /customerservice/customers/123
+
+------------------------------------------------------------------------
+GET /customerservice/customers/123
+------------------------------------------------------------------------
+
+returns a customer instance whose id is 123. The XML document returned:
+
+------------------------------------------------------------------------
+<Customer>
+  <id>123</id>
+  <name>John</name>
+</Customer>
+------------------------------------------------------------------------
+
+A GET request to path /customerservice/orders/223/products/323
+
+------------------------------------------------------------------------
+GET /customerservice/orders/223/products/323
+------------------------------------------------------------------------
+
+returns product 323 that belongs to order 223. The XML document returned:
+
+------------------------------------------------------------------------
+<Product>
+  <description>product 323</description> 
+  <id>323</id> 
+</Product>
+------------------------------------------------------------------------
+
+A POST request to path /customerservice/customers
+
+------------------------------------------------------------------------
+POST /customerservice/customers
+Content-Type: text/xml; charset="utf-8"
+------------------------------------------------------------------------
+
+with the data:
+
+------------------------------------------------------------------------
+<Customer>
+  <name>Jack</name>
+</Customer>
+------------------------------------------------------------------------
+
+adds a customer whose name is Jack 
+
+
+A PUT request to path /customerservice/customers
+
+------------------------------------------------------------------------
+PUT /customerservice/customers
+Content-Type: text/xml; charset="utf-8"
+------------------------------------------------------------------------
+
+with the data:
+
+------------------------------------------------------------------------
+<Customer>
+  <id>123</id>
+  <name>John</name>
+</Customer>
+------------------------------------------------------------------------
+
+updates the customer instance whose id is 123
+
+
+A GET request to path /monitor
+
+------------------------------------------------------------------------
+GET /customerservice/monitor
+------------------------------------------------------------------------
+
+returns a continuous event stream on the customer
+activities.
+
+The client code demonstrates how to send GET/POST/PUT/DELETE requests over
+a websocket.
+
+
+Please review the README in the samples directory before
+continuing.
+
+
+
+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
+  mvn -Pserver  (from one command line window)
+  mvn -Pclient  (from a second command line window)
+
+To remove the target dir, run mvn clean".
+
+Using a web browser that natively supports WebSocket (Safari, Chrome, Firefox):
+After starting the server (see above), open the index.html page located at
+
+  samples/jax_rs/websocket/src/main/resources/index.html
+
+Click on the "Connect" button to establish the websocket connection.
+Fill in the Request and click on the "Send" button. The sent and 
+received data are displayed in the Log area.
+
+Try out the above sample requests. When using POST or PUT with content,
+make sure to have one empty line between the request header and
+the content. For example, the above POST example should use the Request
+value:
+
+------------------------------------------------------------------------
+POST /customerservice/customers
+Content-Type: text/xml; charset="utf-8"
+
+<Customer>
+  <name>Jack</name>
+</Customer>
+------------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cxf/blob/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/pom.xml
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/pom.xml b/distribution/src/main/release/samples/jax_rs/websocket/pom.xml
new file mode 100644
index 0000000..4cd9fd6
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket/pom.xml
@@ -0,0 +1,145 @@
+<?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</artifactId>
+    <name>JAX-RS WebSocket Demo</name>
+    <description>JAX-RS WebSocket Demo</description>
+    <parent>
+        <groupId>org.apache.cxf.samples</groupId>
+        <artifactId>cxf-samples</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+        <relativePath>../..</relativePath>
+    </parent>
+    <properties>
+        <cxf.version>${project.version}</cxf.version>
+        <cxf.ahc.version>1.8.1</cxf.ahc.version>
+        <cxf.jetty.version>8.1.14.v20131031</cxf.jetty.version>
+        <cxf.netty3.version>3.8.0.Final</cxf.netty3.version>
+    </properties>
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <profiles>
+        <profile>
+            <id>server</id>
+            <build>
+                <defaultGoal>test</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>java</goal>
+                                </goals>
+                                <configuration>
+                                    <mainClass>demo.jaxrs.server.Server</mainClass>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>client</id>
+            <build>
+                <defaultGoal>test</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>java</goal>
+                                </goals>
+                                <configuration>
+                                    <mainClass>demo.jaxrs.client.Client</mainClass>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-http</artifactId>
+            <version>3.0.0-SNAPSHOT</version>
+        </dependency>
+        <!-- This dependency is needed if you're using the Jetty container -->
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-websocket</artifactId>
+            <version>3.0.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+            <version>3.0.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>javax.ws.rs-api</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-websocket</artifactId>
+            <version>${cxf.jetty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.ning</groupId>
+            <artifactId>async-http-client</artifactId>
+            <version>${cxf.ahc.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>io.netty</groupId>
+                    <artifactId>netty</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty</artifactId>
+            <version>${cxf.netty3.version}</version>
+        </dependency>
+        <!--  JettyHttpDestination is referring to org.springframework.util.ClassUtils -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+        </dependency>
+        
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/cxf/blob/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/client/Client.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/client/Client.java b/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/client/Client.java
new file mode 100644
index 0000000..4004e84
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/client/Client.java
@@ -0,0 +1,116 @@
+/**
+ * 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.client;
+
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.io.CachedOutputStream;
+
+public final class Client {
+
+    private Client() {
+    }
+
+    public static void main(String args[]) throws Exception {
+        // Sent HTTP GET request to query all customer info
+        /*
+         * URL url = new URL("http://localhost:9000/customers");
+         * System.out.println("Invoking server through HTTP GET to query all
+         * customer info"); InputStream in = url.openStream(); StreamSource
+         * source = new StreamSource(in); printSource(source);
+         */
+
+        // Create a websocket client and connect to the target service
+        WebSocketTestClient client = new WebSocketTestClient("ws://localhost:9000/");
+        client.connect();
+
+        // Sent GET request to query customer info
+        System.out.println("Sent GET request to query customer info");
+        client.sendTextMessage("GET /customerservice/customers/123");
+        client.await(5);
+        List<WebSocketTestClient.Response> responses = client.getReceivedResponses();
+        System.out.println(responses.get(0));
+
+        // Sent GET request to query sub resource product info
+        client.reset(1);
+        System.out.println("Sent GET request to query sub resource product info");
+        client.sendTextMessage("GET /customerservice/orders/223/products/323");
+        client.await(5);
+        responses = client.getReceivedResponses();
+        System.out.println(responses.get(0));
+
+        // Sent PUT request to update customer info
+        client.reset(1);
+        System.out.println("Sent PUT request to update customer info");
+        String inputData = getStringFromInputStream(Client.class.getResourceAsStream("/update_customer.xml"));
+        client.sendTextMessage("PUT /customerservice/customers\r\nContent-Type: text/xml; charset=ISO-8859-1\r\n\r\n" + inputData);
+        client.await(5);
+        responses = client.getReceivedResponses();
+        System.out.println(responses.get(0));
+        
+        // Sent POST request to add customer
+        client.reset(1);
+        System.out.println("Sent POST request to add customer");
+        inputData = getStringFromInputStream(Client.class.getResourceAsStream("/add_customer.xml"));
+        client.sendTextMessage("POST /customerservice/customers\r\nContent-Type: text/xml; charset=ISO-8859-1\r\nAccept: text/xml\r\n\r\n" + inputData);
+        client.await(5);
+        responses = client.getReceivedResponses();
+        System.out.println(responses.get(0));
+
+        // Create another websocket client and connect to the target service
+        WebSocketTestClient client2 = new WebSocketTestClient("ws://localhost:9000/");
+        client2.connect();
+
+        // Sent GET request to monitor the customer activities
+        client2.reset(1);
+        System.out.println("Sent GET request to monitor activities");
+        client2.sendTextMessage("GET /customerservice/monitor");
+        client2.await(5);
+        responses = client2.getReceivedResponses();
+        System.out.println(responses.get(0));
+        
+        // one retrieval, one delete
+        client2.reset(2);
+        client.reset(2);
+        client.sendTextMessage("GET /customerservice/customers/123");
+        client.sendTextMessage("DELETE /customerservice/customers/235");
+
+        client2.await(5);
+        responses = client2.getReceivedResponses();
+        for (Object o : responses) {
+            System.out.println(o);    
+        }
+        
+        client.close();
+        client2.close();
+        System.exit(0);
+    }
+
+    private static String getStringFromInputStream(InputStream in) throws Exception {
+        CachedOutputStream bos = new CachedOutputStream();
+        IOUtils.copy(in, bos);
+        in.close();
+        bos.close();
+        return bos.getOut().toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/client/WebSocketTestClient.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/client/WebSocketTestClient.java b/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/client/WebSocketTestClient.java
new file mode 100644
index 0000000..1d9ad1f
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/client/WebSocketTestClient.java
@@ -0,0 +1,298 @@
+/**
+ * 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.client;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
+
+import com.ning.http.client.AsyncHttpClient;
+import com.ning.http.client.websocket.WebSocket;
+import com.ning.http.client.websocket.WebSocketByteListener;
+import com.ning.http.client.websocket.WebSocketTextListener;
+import com.ning.http.client.websocket.WebSocketUpgradeHandler;
+
+import org.apache.cxf.common.logging.LogUtils;
+
+
+
+/**
+ * Test client to do websocket calls.
+ * @see JAXRSClientServerWebSocketTest
+ * 
+ * we may put this in test-tools so that other systests can use this code.
+ * for now keep it here to experiment jaxrs websocket scenarios.
+ */
+class WebSocketTestClient {
+    private static final Logger LOG = LogUtils.getL7dLogger(WebSocketTestClient.class);
+
+    private List<Object> received;
+    private List<Object> fragments;
+    private CountDownLatch latch;
+    private AsyncHttpClient client;
+    private WebSocket websocket;
+    private String url;
+    
+    public WebSocketTestClient(String url) {
+        this.received = new ArrayList<Object>();
+        this.fragments = new ArrayList<Object>();
+        this.latch = new CountDownLatch(1);
+        this.client = new AsyncHttpClient();
+        this.url = url;
+    }
+    
+    public void connect() throws InterruptedException, ExecutionException, IOException {
+        websocket = client.prepareGet(url).execute(
+            new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WsSocketListener()).build()).get();
+    }
+
+    public void sendTextMessage(String message) {
+        websocket.sendTextMessage(message);
+    }
+
+    public void sendMessage(byte[] message) {
+        websocket.sendMessage(message);
+    }
+    
+    public boolean await(int secs) throws InterruptedException {
+        return latch.await(secs, TimeUnit.SECONDS);
+    }
+    
+    public void reset(int count) {
+        latch = new CountDownLatch(count);
+        received.clear();
+    }
+
+    public List<Object> getReceived() {
+        return received;
+    }
+
+    public List<Response> getReceivedResponses() {
+        Object[] objs = received.toArray();
+        List<Response> responses = new ArrayList<Response>(objs.length);
+        for (Object o : objs) {
+            responses.add(new Response(o));
+        }
+        return responses;
+    }
+    
+    public void close() {
+        websocket.close();
+        client.close();
+    }
+
+    class WsSocketListener implements WebSocketTextListener, WebSocketByteListener {
+
+        public void onOpen(WebSocket ws) {
+            LOG.info("[ws] opened");            
+        }
+
+        public void onClose(WebSocket ws) {
+            LOG.info("[ws] closed");            
+        }
+
+        public void onError(Throwable t) {
+            LOG.info("[ws] error: " + t);                        
+        }
+
+        public void onMessage(byte[] message) {
+            received.add(message);
+            LOG.info("[ws] received bytes --> " + makeString(message));
+            latch.countDown();
+        }
+
+        public void onFragment(byte[] fragment, boolean last) {
+            processFragments(fragment, last);
+        }
+
+        public void onMessage(String message) {
+            received.add(message);
+            LOG.info("[ws] received --> " + message);
+            latch.countDown();
+        }
+
+        public void onFragment(String fragment, boolean last) {
+            processFragments(fragment, last);
+        }
+        
+        private void processFragments(Object f, boolean last) {
+            synchronized (fragments) {
+                fragments.add(f);
+                if (last) {
+                    if (f instanceof String) {
+                        // string
+                        StringBuilder sb = new StringBuilder();
+                        for (Iterator<Object> it = fragments.iterator(); it.hasNext();) {
+                            Object o = it.next();
+                            if (o instanceof String) {
+                                sb.append((String)o);
+                                it.remove();
+                            }
+                        }
+                        received.add(sb.toString());
+                    } else {
+                        // byte[]
+                        ByteArrayOutputStream bao = new ByteArrayOutputStream();
+                        for (Iterator<Object> it = fragments.iterator(); it.hasNext();) {
+                            Object o = it.next();
+                            if (o instanceof byte[]) {
+                                bao.write((byte[])o, 0, ((byte[])o).length);
+                                it.remove();
+                            }
+                        }
+                        received.add(bao.toByteArray());
+                    }
+                }
+            }
+        }
+    }
+    
+    private static String makeString(byte[] data) {
+        return data == null ? null : makeString(data, 0, data.length).toString();
+    }
+
+    private static StringBuilder makeString(byte[] data, int offset, int length) {
+        if (data .length > 256) {
+            return makeString(data, offset, 256).append("...");
+        }
+        StringBuilder xbuf = new StringBuilder().append("\nHEX: ");
+        StringBuilder cbuf = new StringBuilder().append("\nASC: ");
+        for (byte b : data) {
+            writeHex(xbuf, 0xff & b);
+            writePrintable(cbuf, 0xff & b);
+        }
+        return xbuf.append(cbuf);
+    }
+    
+    private static void writeHex(StringBuilder buf, int b) {
+        buf.append(Integer.toHexString(0x100 | (0xff & b)).substring(1)).append(' ');
+    }
+    
+    private static void writePrintable(StringBuilder buf, int b) {
+        if (b == 0x0d) {
+            buf.append("\\r");
+        } else if (b == 0x0a) {
+            buf.append("\\n");
+        } else if (b == 0x09) {
+            buf.append("\\t");
+        } else if ((0x80 & b) != 0) {
+            buf.append('.').append(' ');
+        } else {
+            buf.append((char)b).append(' ');
+        }
+        buf.append(' ');
+    }
+    
+    //TODO this is a temporary way to verify the response; we should come up with something better.
+    public static class Response {
+        private Object data;
+        private int pos; 
+        private int statusCode;
+        private String contentType;
+        private Object entity;
+        
+        public Response(Object data) {
+            this.data = data;
+            String line = readLine();
+            if (line != null) {
+                statusCode = Integer.parseInt(line);
+                while ((line = readLine()) != null) {
+                    if (line.length() > 0) {
+                        int del = line.indexOf(':');
+                        String h = line.substring(0, del).trim();
+                        String v = line.substring(del + 1).trim();
+                        if ("Content-Type".equalsIgnoreCase(h)) {
+                            contentType = v;
+                        }
+                    }
+                }
+            }
+            if (data instanceof String) {
+                entity = ((String)data).substring(pos);
+            } else if (data instanceof byte[]) {
+                entity = new byte[((byte[])data).length - pos];
+                System.arraycopy((byte[])data, pos, (byte[])entity, 0, ((byte[])entity).length);
+            }
+        }
+                
+            
+        
+        public int getStatusCode() {
+            return statusCode;
+        }
+        
+        public String getContentType() {
+            return contentType;
+        }
+        
+        @SuppressWarnings("unused")
+        public Object getEntity() {
+            return entity;
+        }
+        
+        public String getTextEntity() {
+            return gettext(entity);
+        }
+
+        public String toString() {
+            StringBuffer sb = new StringBuffer();
+            sb.append("Status: ").append(statusCode).append("\r\n");
+            sb.append("Type: ").append(contentType).append("\r\n");
+            sb.append("Entity: ").append(gettext(entity)).append("\r\n");
+            return sb.toString();
+        }
+        
+        private String readLine() {
+            StringBuilder sb = new StringBuilder();
+            while (pos < length(data)) {
+                int c = getchar(data, pos++);
+                if (c == '\n') {
+                    break;
+                } else if (c == '\r') {
+                    continue;
+                } else {
+                    sb.append((char)c);
+                }
+            }
+            if (sb.length() == 0) {
+                return null;
+            }
+            return sb.toString();
+        }
+
+        private int length(Object o) {
+            return o instanceof char[] ? ((String)o).length() : (o instanceof byte[] ? ((byte[])o).length : 0);
+        }
+
+        private int getchar(Object o, int p) {
+            return 0xff & (o instanceof String ? ((String)o).charAt(p) : (o instanceof byte[] ? ((byte[])o)[p] : -1));
+        }
+
+        private String gettext(Object o) {
+            return o instanceof String ? (String)o : (o instanceof byte[] ? new String((byte[])o) : null);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Customer.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Customer.java b/distribution/src/main/release/samples/jax_rs/websocket/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/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/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/CustomerService.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/CustomerService.java b/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/CustomerService.java
new file mode 100644
index 0000000..9ba3e05
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/CustomerService.java
@@ -0,0 +1,176 @@
+/**
+ * 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.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+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;
+
+@Path("/customerservice/")
+@Produces("text/xml")
+public class CustomerService {
+    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>();
+    Set<OutputStream> monitors = new HashSet<OutputStream>();
+    
+    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);
+        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 getBookBought() {
+        return new StreamingOutput() {
+            public void write(final OutputStream out) throws IOException, WebApplicationException {
+                monitors.add(out);
+                out.write(("Subscribed at " + new java.util.Date()).getBytes());
+            }
+        };
+    }
+
+    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<OutputStream> it = monitors.iterator(); it.hasNext();) {
+                        OutputStream out = it.next();
+                        try {
+                            out.write(t.getBytes());
+                        } catch (IOException e) {
+                            try {
+                                out.close();
+                            } catch (IOException e2) {
+                                // ignore;
+                            }
+                            it.remove();
+                        }
+                    }
+                } 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);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Order.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Order.java b/distribution/src/main/release/samples/jax_rs/websocket/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/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/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Product.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Product.java b/distribution/src/main/release/samples/jax_rs/websocket/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/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/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Server.java
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Server.java b/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Server.java
new file mode 100644
index 0000000..fe59dd0
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket/src/main/java/demo/jaxrs/server/Server.java
@@ -0,0 +1,45 @@
+/**
+ * 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 org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+
+public class Server {
+
+    protected Server() throws Exception {
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(CustomerService.class);
+        sf.setResourceProvider(CustomerService.class, 
+            new SingletonResourceProvider(new CustomerService()));
+        sf.setAddress("ws://localhost:9000/");
+
+        sf.create();
+    }
+
+    public static void main(String args[]) throws Exception {
+        new Server();
+        System.out.println("Server ready...");
+
+        Thread.sleep(5 * 6000 * 1000);
+        System.out.println("Server exiting");
+        System.exit(0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/add_customer.xml
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/add_customer.xml b/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/add_customer.xml
new file mode 100644
index 0000000..9ef3d4b
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/add_customer.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<Customer>
+    <name>Jack</name>
+</Customer>

http://git-wip-us.apache.org/repos/asf/cxf/blob/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/index.html
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/index.html b/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/index.html
new file mode 100644
index 0000000..2b1cc18
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/index.html
@@ -0,0 +1,172 @@
+<?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.
+
+-->
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>CXF JAX-RS WebSocket Sample</title>  
+</head>
+<body>
+<h2>CXF JAX-RS WebSocket Sample</h2>  
+
+<div id="output">
+  <div id="config" style="float: left;">
+    <strong>Service Endpoint URL:</strong><br />
+    <input id="wsUri" size="72" style="width: 450px" value="ws://localhost:9000/"/>
+    <br/>
+    <button id="connect">Connect</button>
+    <button id="disconnect">Disconnect</button>
+    <br />
+    <br />
+    <strong>Request:</strong><br />
+    <textarea id="request" rows="10" cols="72" style="width: 450px;">GET /customerservice/customers/123</textarea>
+    <br/>
+    <button id="send">Send</button>
+  </div>
+  <div id="log" style="float: left; margin-left: 20px; padding-left: 20px; width: 450px; height: 500px; border-left: solid 1px #cccccc;">
+    <strong>Log:</strong><br />
+    <button id="clearLogBut" style="position: relative; top: 3px;">Clear log</button>
+    <div id="consoleLog" style="margin-top: 5px; border: solid 1px #aaaaaa; overflow-y: scroll; height:100%"></div>
+  </div>
+  <div class="clearfix"></div>
+</div>
+<script language="javascript" type="text/javascript">
+  var output;
+
+  var connectBut = document.getElementById("connect");
+  connectBut.onclick = doConnect;
+
+  var disconnectBut = document.getElementById("disconnect");
+  disconnectBut.onclick = doDisconnect;
+    
+  var request = document.getElementById("request");
+
+  var sendBut = document.getElementById("send");
+  sendBut.onclick = doSend;
+
+  var consoleLog = document.getElementById("consoleLog");
+
+  var clearLogBut = document.getElementById("clearLogBut");
+  clearLogBut.onclick = clearLog;
+
+  function init() {
+    output = document.getElementById("output");
+    setGuiConnected(false);
+  }
+
+  function doConnect() {
+    var wsUri = document.getElementById("wsUri");
+
+    websocket = new WebSocket(wsUri.value);
+    websocket.binaryType = 'arraybuffer';
+
+    websocket.onopen = function(evt) {
+      onOpen(evt)
+    };
+
+    websocket.onclose = function(evt) {
+       onClose(evt)
+    };
+
+    websocket.onmessage = function(evt) {
+      onMessage(evt)
+    };
+
+    websocket.onerror = function(evt) {
+      onError(evt)
+    };
+  }
+
+  function doDisconnect() {
+    websocket.close()
+  }
+
+  function clearLog() {
+    while (consoleLog.childNodes.length > 0) {
+      consoleLog.removeChild(consoleLog.lastChild);
+    }
+  }
+
+  function onOpen(evt) {
+    writeToLog('<span style="color:black; font-size:75%; font-style:italic">CONNECTED</span>');
+    setGuiConnected(true);
+  }
+
+  function onClose(evt) {
+    writeToLog('<span style="color:black; font-size:75%; font-style:italic">DISCONNECTED</span>');
+    setGuiConnected(false);
+  }
+
+  function onMessage(evt) {
+    writeToLog('<span style="color:blue; font-size:75%; font-style:italic">RECEIVED</span><span style="color: blue"><pre>' + createMessage(evt.data) + '</pre></span>');
+  }
+
+  function onError(evt) {
+    writeToLog('<span style="color:red; font-size:75%; font-style:italic">ERROR</span><span style="color: red;"><pre>' + evt.data + '</pre></span>');
+  }
+
+  function doSend(message) {
+    var reqmsg = document.getElementById("request");
+    writeToLog('<span style="color:green; font-size:75%; font-style:italic">SENT</span><span style="color: green;"><pre>' + createMessage(reqmsg.value) + '</pre></span>');
+    websocket.send(reqmsg.value);
+  }
+
+  function setGuiConnected(isConnected) {
+    wsUri.disabled = isConnected;
+    connectBut.disabled = isConnected;
+    disconnectBut.disabled = !isConnected;
+    request.disabled = !isConnected;
+    sendBut.disabled = !isConnected;
+  }
+
+  function createMessage(data) {
+    if (typeof data != 'string') {
+      data = arrayBufferToString(data);
+    }
+    return data.replace(/&/g, '&amp;').replace(/</g, '&lt;');
+  }
+
+  function arrayBufferToString(buf) {
+    var ba = new Uint8Array(buf);
+    var aa = new Array(ba.length);
+    for (i = 0; i < ba.length; i++) {
+      aa[i] = String.fromCharCode(ba[i]);
+    }
+    return Array.prototype.slice.call(aa).join("");
+  }
+
+  function writeToLog(message) {
+    var pre = document.createElement("p");
+    pre.wordWrap = "break-word";
+    pre.innerHTML = message;
+    consoleLog.appendChild(pre);
+
+    while (consoleLog.childNodes.length > 50) {
+      consoleLog.removeChild(consoleLog.firstChild);
+    }
+    
+    consoleLog.scrollTop = consoleLog.scrollHeight;
+  }
+
+  window.addEventListener("load", init, false);
+
+  </script>  
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/cxf/blob/abe5b35e/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/update_customer.xml
----------------------------------------------------------------------
diff --git a/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/update_customer.xml b/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/update_customer.xml
new file mode 100644
index 0000000..228421d
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/websocket/src/main/resources/update_customer.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<Customer>
+    <name>Mary</name>
+    <id>123</id>
+</Customer>


Mime
View raw message