Repository: cxf
Updated Branches:
  refs/heads/master 9a19f69aa -> 1f430d4c7


http://git-wip-us.apache.org/repos/asf/cxf/blob/6755b06c/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/BookStoreWebSocket.java
----------------------------------------------------------------------
diff --git 
a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/BookStoreWebSocket.java
 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/BookStoreWebSocket.java
new file mode 100644
index 0000000..78f032c
--- /dev/null
+++ 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/BookStoreWebSocket.java
@@ -0,0 +1,186 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.http_undertow.websocket;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.StreamingOutput;
+
+import org.apache.cxf.jaxrs.ext.StreamingResponse;
+import org.apache.cxf.transport.websocket.WebSocketConstants;
+
+@Path("/web/bookstore")
+public class BookStoreWebSocket {
+    private static ExecutorService executor = 
Executors.newSingleThreadExecutor();
+    private Map<String, OutputStream> eventsStreams = new HashMap<String, 
OutputStream>();
+
+    @GET
+    @Path("/booknames")
+    @Produces("text/plain")
+    public byte[] getBookName() {
+        return "CXF in Action".getBytes();
+    }
+
+    @GET
+    @Path("/booknames/servletstream")
+    @Produces("text/plain")
+    public void getBookNameStream(@Context HttpServletResponse response) 
throws Exception {
+        OutputStream os = response.getOutputStream();
+        response.setContentType("text/plain");
+        os.write("CXF in Action".getBytes());
+        os.flush();
+    }
+
+    @GET
+    @Path("/books/{id}")
+    @Produces("application/xml")
+    public Book getBook(@PathParam("id") long id) {
+        return new Book("CXF in Action", id);
+    }
+
+    @POST
+    @Path("/booksplain")
+    @Consumes("text/plain")
+    @Produces("text/plain")
+    public Long echoBookId(long theBookId) {
+        return new Long(theBookId);
+    }
+
+    @GET
+    @Path("/bookbought")
+    @Produces("application/*")
+    public StreamingOutput getBookBought() {
+        return new StreamingOutput() {
+            public void write(final OutputStream out) throws IOException, 
WebApplicationException {
+                out.write(("Today: " + new java.util.Date()).getBytes());
+                // just for testing, using a thread
+                executor.execute(new Runnable() {
+                    public void run() {
+                        try {
+                            for (int r = 2, i = 1; i <= 5; r *= 2, i++) {
+                                Thread.sleep(500);
+                                out.write(Integer.toString(r).getBytes());
+                                out.flush();
+                            }
+                            out.close();
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    }
+                });
+            }
+        };
+    }
+
+    @GET
+    @Path("/bookstream")
+    @Produces("application/json")
+    public StreamingResponse<Book> getBookStream() {
+        return new StreamingResponse<Book>() {
+            public void writeTo(final StreamingResponse.Writer<Book> out) 
throws IOException {
+                out.write(new Book("WebSocket1", 1));
+                executor.execute(new Runnable() {
+                    public void run() {
+                        try {
+                            for (int i = 2; i <= 5; i++) {
+                                Thread.sleep(500);
+                                out.write(new Book("WebSocket" + i, i));
+                                out.getEntityStream().flush();
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    }
+                });
+            }
+        };
+    }
+
+    @GET
+    @Path("/hold/{t}")
+    @Produces("text/plain")
+    public String hold(@PathParam("t") long t) {
+        Date from = new Date();
+        try {
+            Thread.sleep(t);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        return "Held from " + from + " for " + t + " ms";
+    }
+
+    @GET
+    @Path("/events/register")
+    @Produces("text/plain")
+    public StreamingOutput 
registerEventsStream(@HeaderParam(WebSocketConstants.DEFAULT_REQUEST_ID_KEY) 
String reqid) {
+        final String key = reqid == null ? "*" : reqid;
+        return new StreamingOutput() {
+            public void write(final OutputStream out) throws IOException, 
WebApplicationException {
+                eventsStreams.put(key, out);
+                out.write(("Registered " + key + " at " + new 
java.util.Date()).getBytes());
+            }
+        };
+
+    }
+
+    @GET
+    @Path("/events/create/{name}")
+    @Produces("text/plain")
+    public String createEvent(@PathParam("name") String name) {
+        for (Iterator<OutputStream> it = eventsStreams.values().iterator(); 
it.hasNext();) {
+            OutputStream out = it.next();
+            try {
+                out.write(("News: event " + name + " created").getBytes());
+                out.flush();
+            } catch (IOException e) {
+                it.remove();
+                e.printStackTrace();
+            }
+        }
+        return name + " created";
+    }
+
+    @GET
+    @Path("/events/unregister/{key}")
+    @Produces("text/plain")
+    public String unregisterEventsStream(@PathParam("key") String key) {
+        return (eventsStreams.remove(key) != null ? "Unregistered: " : 
"Already Unregistered: ") + key;
+    }
+}
+
+

http://git-wip-us.apache.org/repos/asf/cxf/blob/6755b06c/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/Chapter.java
----------------------------------------------------------------------
diff --git 
a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/Chapter.java
 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/Chapter.java
new file mode 100644
index 0000000..dc41db9
--- /dev/null
+++ 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/Chapter.java
@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.http_undertow.websocket;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement(name = "Chapter")
+public class Chapter {
+    private String title;
+    private long id;
+
+    public Chapter() {
+    }
+
+    public void setTitle(String n) {
+        title = n;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setId(long i) {
+        id = i;
+    }
+    public long getId() {
+        return id;
+    }
+
+    @GET
+    @Path("/recurse")
+    @Produces("application/xml")
+    public Chapter getItself() {
+        return this;
+    }
+
+    @Path("/recurse2")
+    public Chapter getItself2() {
+        return this;
+    }
+
+    @GET
+    @Produces("application/xml;charset=ISO-8859-1")
+    public Chapter get() {
+        return this;
+    }
+
+    @GET
+    @Path("/ids")
+    @Produces("application/xml;charset=ISO-8859-1")
+    public Chapter getWithBookId(@PathParam("bookId") int bookId,
+                                 @PathParam("chapterid") int chapterId) {
+        if (bookId != 123 || chapterId != 1) {
+            throw new RuntimeException();
+        }
+        return this;
+    }
+
+
+    @GET
+    @Path("/matched-resources")
+    @Produces("text/plain")
+    public String getMatchedResources(@Context UriInfo ui) {
+        List<String> list = new ArrayList<>();
+        for (Object obj : ui.getMatchedResources()) {
+            list.add(obj.toString());
+        }
+        return list.toString();
+    }
+
+    @GET
+    @Path("/matched%21uris")
+    @Produces("text/plain")
+    public String getMatchedUris(@Context UriInfo ui,
+                                 @QueryParam("decode") String decode) {
+        return ui.getMatchedURIs(Boolean.parseBoolean(decode)).toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/6755b06c/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/JAXRSClientServerWebSocketTest.java
----------------------------------------------------------------------
diff --git 
a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/JAXRSClientServerWebSocketTest.java
 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/JAXRSClientServerWebSocketTest.java
new file mode 100644
index 0000000..bc790a8
--- /dev/null
+++ 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/JAXRSClientServerWebSocketTest.java
@@ -0,0 +1,482 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.http_undertow.websocket;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.transport.websocket.WebSocketConstants;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class JAXRSClientServerWebSocketTest extends 
AbstractBusClientServerTestBase {
+    private static final String PORT = BookServerWebSocket.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        assertTrue("server did not launch correctly", launchServer(new 
BookServerWebSocket()));
+        createStaticBus();
+    }
+
+    @Test
+    public void testBookWithWebSocket() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the GET service
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/booknames").getBytes());
+            assertTrue("one book must be returned", wsclient.await(30000));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals("CXF in Action", value);
+
+            // call the same GET service in the text mode
+            wsclient.reset(1);
+            wsclient.sendTextMessage("GET " +  getContext() + 
"/websocket/web/bookstore/booknames");
+            assertTrue("one book must be returned", wsclient.await(3));
+            received = wsclient.getReceivedResponses();
+            assertEquals(1, received.size());
+            resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            value = resp.getTextEntity();
+            assertEquals("CXF in Action", value);
+
+            // call another GET service
+            wsclient.reset(1);
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/books/123").getBytes());
+            assertTrue("response expected", wsclient.await(3));
+            received = wsclient.getReceivedResponses();
+            resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("application/xml", resp.getContentType());
+            value = resp.getTextEntity();
+            assertTrue(value.startsWith("<?xml ") && 
value.endsWith("</Book>"));
+
+            // call the POST service
+            wsclient.reset(1);
+            wsclient.sendMessage(
+                ("POST " +  getContext() + 
"/websocket/web/bookstore/booksplain\r\nContent-Type: text/plain\r\n\r\n123")
+                    .getBytes());
+            assertTrue("response expected", wsclient.await(3));
+            received = wsclient.getReceivedResponses();
+            resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            value = resp.getTextEntity();
+            assertEquals("123", value);
+
+            // call the same POST service in the text mode
+            wsclient.reset(1);
+            wsclient.sendTextMessage(
+                "POST " +  getContext() + 
"/websocket/web/bookstore/booksplain\r\nContent-Type: text/plain\r\n\r\n123");
+            assertTrue("response expected", wsclient.await(3));
+            received = wsclient.getReceivedResponses();
+            resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            value = resp.getTextEntity();
+            assertEquals("123", value);
+
+            // call the GET service returning a continous stream output
+            wsclient.reset(6);
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/bookbought").getBytes());
+            assertTrue("response expected", wsclient.await(5));
+            received = wsclient.getReceivedResponses();
+            assertEquals(6, received.size());
+            resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("application/octet-stream", resp.getContentType());
+            value = resp.getTextEntity();
+            assertTrue(value.startsWith("Today:"));
+            for (int r = 2, i = 1; i < 6; r *= 2, i++) {
+                // subsequent data should not carry the headers nor the status.
+                resp = received.get(i);
+                assertEquals(0, resp.getStatusCode());
+                assertEquals(r, Integer.parseInt(resp.getTextEntity()));
+            }
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testGetBookStream() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            wsclient.reset(5);
+            wsclient.sendMessage(
+                ("GET " +  getContext() + 
"/websocket/web/bookstore/bookstream\r\nAccept: application/json\r\n\r\n")
+                .getBytes());
+            assertTrue("response expected", wsclient.await(5));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(5, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("application/json", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals(value, getBookJson(1));
+            for (int i = 2; i <= 5; i++) {
+                // subsequent data should not carry the headers nor the status.
+                resp = received.get(i - 1);
+                assertEquals(0, resp.getStatusCode());
+                assertEquals(resp.getTextEntity(), getBookJson(i));
+            }
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testGetBookStreamWithIDReferences() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            wsclient.reset(5);
+            String reqid = UUID.randomUUID().toString();
+            wsclient.sendMessage(
+                ("GET " +  getContext() + 
"/websocket/web/bookstore/bookstream\r\nAccept: application/json\r\n"
+                    + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + ": " + reqid 
+ "\r\n\r\n")
+                .getBytes());
+            assertTrue("response expected", wsclient.await(5));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(5, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("application/json", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals(value, getBookJson(1));
+            for (int i = 2; i <= 5; i++) {
+                // subsequent data should not carry the status but the id 
header
+                resp = received.get(i - 1);
+                assertEquals(0, resp.getStatusCode());
+                assertEquals(reqid, resp.getId());
+                assertEquals(resp.getTextEntity(), getBookJson(i));
+            }
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    private String getBookJson(int index) {
+        return "{\"Book\":{\"id\":" + index + ",\"name\":\"WebSocket" + index 
+ "\"}}";
+    }
+
+    @Test
+    public void testBookWithWebSocketAndHTTP() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the GET service
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/booknames").getBytes());
+            assertTrue("one book must be returned", wsclient.await(3));
+            List<Object> received = wsclient.getReceived();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = new 
WebSocketTestClient.Response(received.get(0));
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals("CXF in Action", value);
+
+            testGetBookHTTPFromWebSocketEndpoint();
+
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testGetBookHTTPFromWebSocketEndpoint() throws Exception {
+        String address = "http://localhost:"; + getPort() + getContext() + 
"/websocket/web/bookstore/books/1";
+        WebClient wc = WebClient.create(address);
+        wc.accept("application/xml");
+        Book book = wc.get(Book.class);
+        assertEquals(1L, book.getId());
+    }
+
+    @Test
+    public void testBookWithWebSocketServletStream() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/booknames/servletstream")
+                                 .getBytes());
+            assertTrue("one book must be returned", wsclient.await(3));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals("CXF in Action", value);
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testWrongMethod() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the GET service using POST
+            wsclient.reset(1);
+            wsclient.sendMessage(("POST " +  getContext() + 
"/websocket/web/bookstore/booknames").getBytes());
+            assertTrue("error response expected", wsclient.await(3));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(405, resp.getStatusCode());
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testPathRestriction() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the GET service over the different path
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/bookstore2").getBytes());
+            assertTrue("error response expected", wsclient.await(3));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(404, resp.getStatusCode());
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testCallsWithIDReferences() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the POST service without requestId
+            wsclient.sendTextMessage(
+                "POST " +  getContext() + 
"/websocket/web/bookstore/booksplain\r\nContent-Type: text/plain\r\n\r\n459");
+            assertTrue("response expected", wsclient.await(3));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals("459", value);
+            String id = resp.getId();
+            assertNull("response id is incorrect", id);
+
+            // call the POST service twice with a unique requestId
+            wsclient.reset(2);
+            String reqid1 = UUID.randomUUID().toString();
+            String reqid2 = UUID.randomUUID().toString();
+            wsclient.sendTextMessage(
+                "POST " +  getContext() + 
"/websocket/web/bookstore/booksplain\r\nContent-Type: text/plain\r\n"
+                + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + ": " + reqid1 + 
"\r\n\r\n549");
+            wsclient.sendTextMessage(
+                "POST " +  getContext() + 
"/websocket/web/bookstore/booksplain\r\nContent-Type: text/plain\r\n"
+                + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + ": " + reqid2 + 
"\r\n\r\n495");
+            assertTrue("response expected", wsclient.await(3));
+            received = wsclient.getReceivedResponses();
+            for (WebSocketTestClient.Response r : received) {
+                assertEquals(200, r.getStatusCode());
+                assertEquals("text/plain", r.getContentType());
+                value = r.getTextEntity();
+                id = r.getId();
+                if (reqid1.equals(id)) {
+                    assertEquals("549", value);
+                } else if (reqid2.equals(id)) {
+                    assertEquals("495", value);
+                } else {
+                    fail("unexpected responseId: " + id);
+                }
+            }
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testCallsInParallel() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the GET service that takes a long time to response
+            wsclient.reset(2);
+            wsclient.sendTextMessage(
+                "GET " +  getContext() + "/websocket/web/bookstore/hold/3000");
+            wsclient.sendTextMessage(
+                "GET " +  getContext() + "/websocket/web/bookstore/hold/3000");
+            // each call takes 3 seconds but executed in parallel, so waiting 
4 secs is sufficient
+            assertTrue("response expected", wsclient.await(4));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(2, received.size());
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testStreamRegisterAndUnregister() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient1 = new WebSocketTestClient(address);
+        WebSocketTestClient wsclient2 = new WebSocketTestClient(address);
+        wsclient1.connect();
+        wsclient2.connect();
+        try {
+            String regkey = UUID.randomUUID().toString();
+
+            EventCreatorRunner runner = new EventCreatorRunner(wsclient2, 
regkey, 1000, 1000);
+            new Thread(runner).start();
+
+            // register for the event stream with requestId ane expect to get 
2 messages
+            wsclient1.reset(3);
+            wsclient1.sendTextMessage(
+                "GET " +  getContext() + 
"/websocket/web/bookstore/events/register\r\n"
+                    + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + ": " + 
regkey + "\r\n\r\n");
+            assertFalse("only 2 responses expected", wsclient1.await(5));
+            List<WebSocketTestClient.Response> received = 
wsclient1.getReceivedResponses();
+            assertEquals(2, received.size());
+
+            // the first response is the registration confirmation
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertTrue(value.startsWith("Registered " + regkey));
+            String id = resp.getId();
+            assertEquals("unexpected responseId", regkey, id);
+
+            // the second response is the event news
+            resp = received.get(1);
+            assertEquals(0, resp.getStatusCode());
+            value = resp.getTextEntity();
+            assertEquals("News: event Hello created", value);
+            id = resp.getId();
+            assertEquals("unexpected responseId", regkey, id);
+
+            String[] values = runner.getValues();
+            assertTrue(runner.isCompleted());
+            assertEquals("Hello created", values[0]);
+            assertTrue(values[1].startsWith("Unregistered: " + regkey));
+            assertEquals("Hola created", values[2]);
+        } finally {
+            wsclient1.close();
+            wsclient2.close();
+        }
+    }
+
+    private class EventCreatorRunner implements Runnable {
+        private WebSocketTestClient wsclient;
+        private String key;
+        private long delay1;
+        private long delay2;
+        private String[] values = new String[3];
+        private boolean completed;
+
+        EventCreatorRunner(WebSocketTestClient wsclient, String key, long 
delay1, long delay2) {
+            this.wsclient = wsclient;
+            this.key = key;
+            this.delay1 = delay1;
+            this.delay2 = delay2;
+        }
+
+        public void run() {
+            try {
+                Thread.sleep(delay1);
+                // creating an event and the event stream will see this event
+                wsclient.sendTextMessage(
+                    "GET " +  getContext() + 
"/websocket/web/bookstore/events/create/Hello\r\n\r\n");
+                assertTrue("response expected", wsclient.await(3));
+                List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+                WebSocketTestClient.Response resp = received.get(0);
+                values[0] = resp.getTextEntity();
+
+                Thread.sleep(delay2);
+                wsclient.reset(1);
+                // unregistering the event stream
+                wsclient.sendTextMessage(
+                    "GET " +  getContext() + 
"/websocket/web/bookstore/events/unregister/" + key + "\r\n\r\n");
+                assertTrue("response expected", wsclient.await(3));
+                received = wsclient.getReceivedResponses();
+                resp = received.get(0);
+                values[1] = resp.getTextEntity();
+
+                wsclient.reset(1);
+                // creating another event and the event stream will not see 
this event
+                wsclient.sendTextMessage(
+                    "GET " +  getContext() + 
"/websocket/web/bookstore/events/create/Hola\r\n\r\n");
+                assertTrue("response expected", wsclient.await(3));
+                received = wsclient.getReceivedResponses();
+                resp = received.get(0);
+                values[2] = resp.getTextEntity();
+            } catch (InterruptedException e) {
+                // ignore
+            } finally {
+                completed = true;
+            }
+        }
+
+        public String[] getValues() {
+            return values;
+        }
+
+        public boolean isCompleted() {
+            return completed;
+        }
+    }
+
+    protected String getPort() {
+        return PORT;
+    }
+    protected String getContext() {
+        return "";
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/6755b06c/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/JAXRSClientServerWebSocketTest.java.bak
----------------------------------------------------------------------
diff --git 
a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/JAXRSClientServerWebSocketTest.java.bak
 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/JAXRSClientServerWebSocketTest.java.bak
new file mode 100644
index 0000000..4747965
--- /dev/null
+++ 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/JAXRSClientServerWebSocketTest.java.bak
@@ -0,0 +1,438 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.http_undertow.websocket;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.transport.websocket.WebSocketConstants;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class JAXRSClientServerWebSocketTest extends 
AbstractBusClientServerTestBase {
+    private static final String PORT = BookServerWebSocket.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        assertTrue("server did not launch correctly", launchServer(new 
BookServerWebSocket()));
+        createStaticBus();
+    }
+
+    @Test
+    public void testBookWithWebSocket() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);       
 
+        wsclient.connect();
+        
+        try {
+            // call the GET service
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/booknames").getBytes());
+            assertTrue("one book must be returned", wsclient.await(500));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals("CXF in Action", value);
+
+            
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testGetBookStream() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            wsclient.reset(5);
+            wsclient.sendMessage(
+                ("GET " +  getContext() + 
"/websocket/web/bookstore/bookstream\r\nAccept: application/json\r\n\r\n")
+                .getBytes());
+            assertTrue("response expected", wsclient.await(15));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(5, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("application/json", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals(value, getBookJson(1));
+            for (int i = 2; i <= 5; i++) {
+                // subsequent data should not carry the headers nor the status.
+                resp = received.get(i - 1);
+                assertEquals(0, resp.getStatusCode());
+                assertEquals(resp.getTextEntity(), getBookJson(i));
+            }
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testGetBookStreamWithIDReferences() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            wsclient.reset(5);
+            String reqid = UUID.randomUUID().toString();
+            wsclient.sendMessage(
+                ("GET " +  getContext() + 
"/websocket/web/bookstore/bookstream\r\nAccept: application/json\r\n"
+                    + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + ": " + reqid 
+ "\r\n\r\n")
+                .getBytes());
+            assertTrue("response expected", wsclient.await(50));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(5, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("application/json", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals(value, getBookJson(1));
+            for (int i = 2; i <= 5; i++) {
+                // subsequent data should not carry the status but the id 
header
+                resp = received.get(i - 1);
+                assertEquals(0, resp.getStatusCode());
+                assertEquals(reqid, resp.getId());
+                assertEquals(resp.getTextEntity(), getBookJson(i));
+            }
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    private String getBookJson(int index) {
+        return "{\"Book\":{\"id\":" + index + ",\"name\":\"WebSocket" + index 
+ "\"}}";
+    }
+
+    @Test
+    public void testBookWithWebSocketAndHTTP() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the GET service
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/booknames").getBytes());
+            assertTrue("one book must be returned", wsclient.await(3));
+            List<Object> received = wsclient.getReceived();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = new 
WebSocketTestClient.Response(received.get(0));
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals("CXF in Action", value);
+
+            testGetBookHTTPFromWebSocketEndpoint();
+
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testGetBookHTTPFromWebSocketEndpoint() throws Exception {
+        String address = "http://localhost:"; + getPort() + getContext() + 
"/websocket/web/bookstore/books/1";
+        WebClient wc = WebClient.create(address);
+        wc.accept("application/xml");
+        Book book = wc.get(Book.class);
+        assertEquals(1L, book.getId());
+    }
+
+    @Test
+    public void testBookWithWebSocketServletStream() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/booknames/servletstream")
+                                 .getBytes());
+            assertTrue("one book must be returned", wsclient.await(3));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals("CXF in Action", value);
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testWrongMethod() throws Exception {
+        String address = "ws://127.0.0.1:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the GET service using POST
+            wsclient.reset(1);
+            wsclient.sendMessage(("POST " +  getContext() + 
"/websocket/web/bookstore/booknames").getBytes());
+            assertTrue("error response expected", wsclient.await(3));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(405, resp.getStatusCode());
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testPathRestriction() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the GET service over the different path
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/bookstore2").getBytes());
+            assertTrue("error response expected", wsclient.await(3));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(1, received.size());
+            WebSocketTestClient.Response resp = received.get(0);
+            //assertEquals(400, resp.getStatusCode()); TODO later
+            assertEquals(404, resp.getStatusCode());
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testCallsWithIDReferences() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the POST service without requestId
+            wsclient.sendMessage(
+                ("POST " +  getContext() 
+                + "/websocket/web/bookstore/booksplain\r\nContent-Type: 
text/plain\r\n\r\n459").getBytes());
+            assertTrue("response expected", wsclient.await(300));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertEquals("459", value);
+            String id = resp.getId();
+            assertNull("response id is incorrect", id);
+
+            // call the POST service twice with a unique requestId
+            wsclient.reset(2);
+            String reqid1 = UUID.randomUUID().toString();
+            String reqid2 = UUID.randomUUID().toString();
+            /*wsclient
+                .sendMessage(("POST " + getContext()
+                                 + 
"/websocket/web/bookstore/booksplain\r\nContent-Type: text/plain\r\n"
+                                 + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + 
": " 
+                                 + reqid1 + "\r\n\r\n549").getBytes());
+            wsclient
+                .sendMessage(("POST " + getContext()
+                                 + 
"/websocket/web/bookstore/booksplain\r\nContent-Type: text/plain\r\n"
+                                 + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + 
": " 
+                                 + reqid2 + "\r\n\r\n495").getBytes());*/
+            wsclient.sendTextMessage(
+                "POST " +  getContext() + 
"/websocket/web/bookstore/booksplain\r\nContent-Type: text/plain\r\n"
+                + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + ": " + reqid1 + 
"\r\n\r\n549");
+            wsclient.sendTextMessage(
+                "POST " +  getContext() + 
"/websocket/web/bookstore/booksplain\r\nContent-Type: text/plain\r\n"
+                + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + ": " + reqid2 + 
"\r\n\r\n495");
+            assertTrue("response expected", wsclient.await(300));
+            received = wsclient.getReceivedResponses();
+            for (WebSocketTestClient.Response r : received) {
+                assertEquals(200, r.getStatusCode());
+                assertEquals("text/plain", r.getContentType());
+                value = r.getTextEntity();
+                id = r.getId();
+                if (reqid1.equals(id)) {
+                    assertEquals("549", value);
+                } else if (reqid2.equals(id)) {
+                    assertEquals("495", value);
+                } else {
+                    fail("unexpected responseId: " + id);
+                }
+            }
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testCallsInParallel() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient = new WebSocketTestClient(address);
+        wsclient.connect();
+        try {
+            // call the GET service that takes a long time to response
+            wsclient.reset(2);
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/hold/3000").getBytes());
+            wsclient.sendMessage(("GET " +  getContext() + 
"/websocket/web/bookstore/hold/3000").getBytes());
+            /*wsclient.sendTextMessage(
+                "GET " +  getContext() + "/websocket/web/bookstore/hold/3000");
+            wsclient.sendTextMessage(
+                "GET " +  getContext() + 
"/websocket/web/bookstore/hold/3000");*/
+            // each call takes 3 seconds but executed in parallel, so waiting 
4 secs is sufficient
+            assertTrue("response expected", wsclient.await(20));
+            List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+            assertEquals(2, received.size());
+        } finally {
+            wsclient.close();
+        }
+    }
+
+    @Test
+    public void testStreamRegisterAndUnregister() throws Exception {
+        String address = "ws://localhost:" + getPort() + getContext() + 
"/websocket/web/bookstore";
+
+        WebSocketTestClient wsclient1 = new WebSocketTestClient(address);
+        WebSocketTestClient wsclient2 = new WebSocketTestClient(address);
+        wsclient1.connect();
+        wsclient2.connect();
+        try {
+            String regkey = UUID.randomUUID().toString();
+
+            EventCreatorRunner runner = new EventCreatorRunner(wsclient2, 
regkey, 1000, 1000);
+            new Thread(runner).start();
+
+            // register for the event stream with requestId ane expect to get 
2 messages
+            wsclient1.reset(3);
+            wsclient1.sendMessage(
+                 ("GET " +  getContext() + 
"/websocket/web/bookstore/events/register\r\n"
+                                          + 
WebSocketConstants.DEFAULT_REQUEST_ID_KEY + ": " 
+                     + regkey + "\r\n\r\n").getBytes());
+            /*wsclient1.sendTextMessage(
+                "GET " +  getContext() + 
"/websocket/web/bookstore/events/register\r\n"
+                    + WebSocketConstants.DEFAULT_REQUEST_ID_KEY + ": " + 
regkey + "\r\n\r\n");*/
+            assertFalse("only 2 responses expected", wsclient1.await(25));
+            List<WebSocketTestClient.Response> received = 
wsclient1.getReceivedResponses();
+            assertEquals(2, received.size());
+
+            // the first response is the registration confirmation
+            WebSocketTestClient.Response resp = received.get(0);
+            assertEquals(200, resp.getStatusCode());
+            assertEquals("text/plain", resp.getContentType());
+            String value = resp.getTextEntity();
+            assertTrue(value.startsWith("Registered " + regkey));
+            String id = resp.getId();
+            assertEquals("unexpected responseId", regkey, id);
+
+            // the second response is the event news
+            resp = received.get(1);
+            assertEquals(0, resp.getStatusCode());
+            value = resp.getTextEntity();
+            assertEquals("News: event Hello created", value);
+            id = resp.getId();
+            assertEquals("unexpected responseId", regkey, id);
+
+            String[] values = runner.getValues();
+            assertTrue(runner.isCompleted());
+            assertEquals("Hello created", values[0]);
+            assertTrue(values[1].startsWith("Unregistered: " + regkey));
+            assertEquals("Hola created", values[2]);
+        } finally {
+            wsclient1.close();
+            wsclient2.close();
+        }
+    }
+
+    private class EventCreatorRunner implements Runnable {
+        private WebSocketTestClient wsclient;
+        private String key;
+        private long delay1;
+        private long delay2;
+        private String[] values = new String[3];
+        private boolean completed;
+
+        EventCreatorRunner(WebSocketTestClient wsclient, String key, long 
delay1, long delay2) {
+            this.wsclient = wsclient;
+            this.key = key;
+            this.delay1 = delay1;
+            this.delay2 = delay2;
+        }
+
+        public void run() {
+            try {
+                Thread.sleep(delay1);
+                // creating an event and the event stream will see this event
+                wsclient.sendMessage(
+                    ("GET " +  getContext() + 
"/websocket/web/bookstore/events/create/Hello\r\n\r\n").getBytes());
+                assertTrue("response expected", wsclient.await(3));
+                List<WebSocketTestClient.Response> received = 
wsclient.getReceivedResponses();
+                WebSocketTestClient.Response resp = received.get(0);
+                values[0] = resp.getTextEntity();
+
+                Thread.sleep(delay2);
+                wsclient.reset(1);
+                // unregistering the event stream
+                wsclient.sendMessage(
+                    ("GET " +  getContext() + 
"/websocket/web/bookstore/events/unregister/" 
+                        + key + "\r\n\r\n").getBytes());
+                assertTrue("response expected", wsclient.await(3));
+                received = wsclient.getReceivedResponses();
+                resp = received.get(0);
+                values[1] = resp.getTextEntity();
+
+                wsclient.reset(1);
+                // creating another event and the event stream will not see 
this event
+                wsclient.sendMessage(
+                    ("GET " +  getContext() + 
"/websocket/web/bookstore/events/create/Hola\r\n\r\n").getBytes());
+                assertTrue("response expected", wsclient.await(3));
+                received = wsclient.getReceivedResponses();
+                resp = received.get(0);
+                values[2] = resp.getTextEntity();
+            } catch (InterruptedException e) {
+                // ignore
+            } finally {
+                completed = true;
+            }
+        }
+
+        public String[] getValues() {
+            return values;
+        }
+
+        public boolean isCompleted() {
+            return completed;
+        }
+    }
+
+    protected String getPort() {
+        return PORT;
+    }
+    protected String getContext() {
+        return "";
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/6755b06c/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/SuperBook.java
----------------------------------------------------------------------
diff --git 
a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/SuperBook.java
 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/SuperBook.java
new file mode 100644
index 0000000..5ffac9c
--- /dev/null
+++ 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/SuperBook.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 org.apache.cxf.systest.http_undertow.websocket;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement(name = "SuperBook")
+public class SuperBook extends Book implements SuperBookInterface {
+    private boolean superBook;
+
+    public SuperBook() {
+
+    }
+
+    public SuperBook(String name, long id, boolean superStatus) {
+        super(name, id);
+        this.superBook = superStatus;
+    }
+
+    public boolean isSuperBook() {
+        return superBook;
+    }
+
+    public void setSuperBook(boolean superBook) {
+        this.superBook = superBook;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/6755b06c/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/SuperBookInterface.java
----------------------------------------------------------------------
diff --git 
a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/SuperBookInterface.java
 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/SuperBookInterface.java
new file mode 100644
index 0000000..ff8b628
--- /dev/null
+++ 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/SuperBookInterface.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.http_undertow.websocket;
+
+public interface SuperBookInterface {
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/6755b06c/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/WebSocketTestClient.java
----------------------------------------------------------------------
diff --git 
a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/WebSocketTestClient.java
 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/WebSocketTestClient.java
new file mode 100644
index 0000000..ffb46bf
--- /dev/null
+++ 
b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/websocket/WebSocketTestClient.java
@@ -0,0 +1,329 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.http_undertow.websocket;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+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.ws.WebSocket;
+import com.ning.http.client.ws.WebSocketByteListener;
+import com.ning.http.client.ws.WebSocketTextListener;
+import com.ning.http.client.ws.WebSocketUpgradeHandler;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.transport.websocket.WebSocketConstants;
+
+
+
+/**
+ * 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;
+
+    WebSocketTestClient(String url) {
+        this.received = Collections.synchronizedList(new ArrayList<>());
+        this.fragments = Collections.synchronizedList(new ArrayList<>());
+        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();
+        if (websocket == null) {
+            throw new NullPointerException("websocket is null");
+        }
+    }
+
+    public void sendTextMessage(String message) {
+        websocket.sendMessage(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<>(objs.length);
+        for (Object o : objs) {
+            responses.add(new Response(o));
+        }
+        return responses;
+    }
+
+    public void close() {
+        if (websocket != null) {
+            websocket.close();
+        }
+        if (client != null) {
+            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) {
+            LOG.info("[ws] received fragment bytes (last?" + last + ") --> " + 
fragment);
+            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) {
+            LOG.info("[ws] received fragment (last?" + last + ") --> " + 
fragment);
+            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 String id;
+        private Object entity;
+
+        Response(Object data) {
+            this.data = data;
+            String line;
+            boolean first = true;
+            while ((line = readLine()) != null) {
+                if (first && isStatusCode(line)) {
+                    statusCode = Integer.parseInt(line);
+                    continue;
+                } else {
+                    first = false;
+                }
+
+                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;
+                } else if 
(WebSocketConstants.DEFAULT_RESPONSE_ID_KEY.equals(h)) {
+                    id = 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);
+            }
+        }
+
+        private static boolean isStatusCode(String line) {
+            char c = line.charAt(0);
+            return '0' <= c && c <= '9';
+        }
+
+        public int getStatusCode() {
+            return statusCode;
+        }
+
+        public String getContentType() {
+            return contentType;
+        }
+
+        public Object getEntity() {
+            return entity;
+        }
+
+        public String getTextEntity() {
+            return gettext(entity);
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            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) {
+            if (o instanceof String) {
+                return ((String)o).length();
+            } else if (o instanceof char[]) {
+                return ((char[])o).length;
+            } else if (o instanceof byte[]) {
+                return ((byte[])o).length;
+            } else {
+                return 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);
+        }
+    }
+}

Reply via email to