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 2014/03/24 10:58:07 UTC
git commit: add a jaxrs websocket browser demo in the sample
collection
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, '&').replace(/</g, '<');
+ }
+
+ 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>