cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a.@apache.org
Subject [1/2] refactor websocket (CXF-5339) into a seprate transport component
Date Mon, 10 Mar 2014 15:50:39 GMT
Repository: cxf
Updated Branches:
  refs/heads/master c9c443054 -> 8fe4fc13a


http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocket.java
----------------------------------------------------------------------
diff --git a/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocket.java b/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocket.java
new file mode 100644
index 0000000..92c6525
--- /dev/null
+++ b/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocket.java
@@ -0,0 +1,1111 @@
+/**
+ * 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.transport.websocket.jetty;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.Part;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.helpers.CastUtils;
+import org.eclipse.jetty.websocket.WebSocket;
+
+class JettyWebSocket implements WebSocket.OnBinaryMessage, WebSocket.OnTextMessage {
+    private static final Logger LOG = LogUtils.getL7dLogger(JettyWebSocket.class);
+    private static final String CRLF = "\r\n";
+
+    private static final String URI_KEY = "$uri";
+    private static final String METHOD_KEY = "$method";
+    private static final String SC_KEY = "$sc";
+    private static final String SM_KEY = "$sm";
+    private static final String FLUSHED_KEY = "$flushed";
+    
+    private JettyWebSocketManager manager;
+    private ServletContext servletContext;
+    private Connection webSocketConnection;
+    private Map<String, Object> requestProperties;
+    private String protocol;
+    
+    public JettyWebSocket(JettyWebSocketManager manager, HttpServletRequest request, String protocol) {
+        this.manager = manager;
+        this.protocol = protocol;
+        this.requestProperties = readProperties(request);
+    }
+    
+    private Map<String, Object> readProperties(HttpServletRequest request) {
+        Map<String, Object> properties = new HashMap<String, Object>();
+        properties.put("servletPath", request.getServletPath());
+        properties.put("requestURI", request.getRequestURI());
+        properties.put("requestURL", request.getRequestURL().toString());
+        properties.put("contextPath", request.getContextPath());
+        properties.put("servletPath", request.getServletPath());
+        properties.put("pathInfo", request.getPathInfo());
+        properties.put("pathTranslated", request.getPathTranslated());
+        properties.put("protocol", request.getProtocol());
+        properties.put("scheme", request.getScheme());
+        // some additional ones
+        properties.put("localAddr", request.getLocalAddr());
+        properties.put("localName", request.getLocalName());
+        properties.put("localPort", request.getLocalPort());
+        properties.put("locale", request.getLocale());
+        properties.put("locales", request.getLocales());
+        properties.put("remoteHost", request.getRemoteHost());
+        properties.put("remoteAddr", request.getRemoteAddr());
+        properties.put("serverName", request.getServerName());
+        properties.put("secure", request.isSecure());
+        properties.put("authType", request.getAuthType());
+        properties.put("dispatcherType", request.getDispatcherType());
+        
+        return properties;
+    }
+
+    @Override
+    public void onClose(int closeCode, String message) {
+        if (LOG.isLoggable(Level.INFO)) {
+            LOG.log(Level.INFO, "onClose({0}, {1})", new Object[]{closeCode, message});
+        }
+        this.webSocketConnection = null;
+    }
+
+    @Override
+    public void onOpen(Connection connection) {
+        if (LOG.isLoggable(Level.INFO)) {
+            LOG.log(Level.INFO, "onOpen({0}))", connection);
+        }
+        this.webSocketConnection = connection;
+    }
+
+    @Override
+    public void onMessage(String data) {
+        if (LOG.isLoggable(Level.INFO)) {
+            LOG.log(Level.INFO, "onMessage({0})", data);
+        }
+        try {
+            byte[] bdata = data.getBytes("utf-8");
+            HttpServletRequest request = createServletRequest(bdata, 0, bdata.length);
+            HttpServletResponse response = createServletResponse();
+            if (manager != null) {
+                manager.service(request, response);    
+            }
+        } catch (Exception e) {
+            LOG.log(Level.WARNING, "Failed to invoke service", e);
+        }            
+    }
+
+    @Override
+    public void onMessage(byte[] data, int offset, int length) {
+        if (LOG.isLoggable(Level.INFO)) {
+            LOG.log(Level.INFO, "onMessage({0}, {1}, {2})", new Object[]{data, offset, length});
+        }
+        try {
+            HttpServletRequest request = createServletRequest(data, offset, length);
+            HttpServletResponse response = createServletResponse();
+            if (manager != null) {
+                manager.service(request, response);
+            }
+        } catch (Exception e) {
+            LOG.log(Level.WARNING, "Failed to invoke service", e);
+        }
+    }
+    
+    private <T> T getRequestProperty(String name, Class<T> cls) {
+        return getValue(requestProperties, name, cls);
+    }
+    
+    private WebSocketVirtualServletRequest createServletRequest(byte[] data, int offset, int length) 
+        throws IOException {
+        return new WebSocketVirtualServletRequest(servletContext, this, new ByteArrayInputStream(data, offset, length));
+    }
+
+    private WebSocketVirtualServletResponse createServletResponse() throws IOException {
+        return new WebSocketVirtualServletResponse(this);
+    }
+    
+    /**
+     * Writes to the underlining socket.
+     * 
+     * @param data
+     * @param offset
+     * @param length
+     */
+    void write(byte[] data, int offset, int length) throws IOException {
+        LOG.log(Level.INFO, "write(byte[], offset, length)");
+        webSocketConnection.sendMessage(data, offset, length);
+    }
+
+    private static byte[] buildResponse(Map<String, String> headers, byte[] data, int offset, int length) {
+        StringBuilder sb = new StringBuilder();
+        String v = headers.get(SC_KEY);
+        sb.append(v == null ? "200" : v).append(CRLF);
+        v = headers.get("Content-Type");
+        if (v != null) {
+            sb.append("Content-Type: ").append(v).append(CRLF);
+        }
+        sb.append(CRLF);
+        
+        byte[] hb = sb.toString().getBytes();
+        byte[] longdata = new byte[hb.length + length];
+        System.arraycopy(hb, 0, longdata, 0, hb.length);
+        if (data != null && length > 0) {
+            System.arraycopy(data, offset, longdata, hb.length, length);
+        }
+        return longdata;
+    }
+
+    private static byte[] buildResponse(byte[] data, int offset, int length) {
+        byte[] longdata = new byte[length + 2];
+        longdata[0] = 0x0d;
+        longdata[1] = 0x0a;
+        System.arraycopy(data, offset, longdata, 2, length);
+        return longdata;
+    }
+    
+    ServletOutputStream getServletOutputStream(final Map<String, String> headers) {
+        LOG.log(Level.INFO, "getServletOutputStream()");
+        return new ServletOutputStream() {
+
+            @Override
+            public void write(int b) throws IOException {
+                byte[] data = new byte[1];
+                data[0] = (byte)b;
+                write(data, 0, 1);
+            }
+
+            @Override
+            public void write(byte[] data, int offset, int length) throws IOException {
+                if (headers.get(FLUSHED_KEY) == null) {
+                    data = buildResponse(headers, data, offset, length);
+                    headers.put(FLUSHED_KEY, "true");
+                } else {
+                    data = buildResponse(data, offset, length);
+                }
+                webSocketConnection.sendMessage(data, 0, data.length);
+            }
+
+            @Override
+            public void close() throws IOException {
+                if (headers.get(FLUSHED_KEY) == null) {
+                    byte[] data = buildResponse(headers, null, 0, 0);
+                    webSocketConnection.sendMessage(data, 0, data.length);
+                    headers.put(FLUSHED_KEY, "true");
+                }                
+                super.close();
+            }
+            
+        };
+    }
+    
+    OutputStream getOutputStream(final Map<String, String> headers) {
+        LOG.log(Level.INFO, "getOutputStream()");
+        return new OutputStream() {
+
+            @Override
+            public void write(int b) throws IOException {
+                byte[] data = new byte[1];
+                data[0] = (byte)b;
+                write(data, 0, 1);
+            }
+            
+            @Override
+            public void write(byte[] data, int offset, int length) throws IOException {
+                if (headers.get(FLUSHED_KEY) == null) {
+                    data = buildResponse(headers, data, offset, length);
+                    headers.put(FLUSHED_KEY, "true");
+                } else {
+                    data = buildResponse(data, offset, length);
+                }
+                webSocketConnection.sendMessage(data, 0, data.length);
+            }
+
+            @Override
+            public void close() throws IOException {
+                if (headers.get(FLUSHED_KEY) == null) {
+                    byte[] data = buildResponse(headers, null, 0, 0);
+                    webSocketConnection.sendMessage(data, 0, data.length);
+                    headers.put(FLUSHED_KEY, "true");
+                }                
+                super.close();
+            }
+        };
+        
+    }
+    
+    String getProtocol() {
+        return protocol;
+    }
+    
+    // 
+    static class WebSocketVirtualServletRequest implements HttpServletRequest {
+        private ServletContext context;
+        private JettyWebSocket websocket;
+        private InputStream in;
+        private Map<String, String> requestHeaders;
+        private Map<String, Object> attributes;
+        
+        public WebSocketVirtualServletRequest(ServletContext context, JettyWebSocket websocket, InputStream in) 
+            throws IOException {
+            this.context = context;
+            this.websocket = websocket;
+            this.in = in;
+
+            this.requestHeaders = readHeaders(in);
+            String path = requestHeaders.get(URI_KEY);
+            String origin = websocket.getRequestProperty("requestURI", String.class);
+            if (!path.startsWith(origin)) {
+                //REVISIT for now, log it here and reject the request later.  
+                LOG.log(Level.WARNING, "invalid path: {0} not within {1}", new Object[]{path, origin});
+            }
+            this.attributes = new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER);
+        }
+
+        @Override
+        public AsyncContext getAsyncContext() {
+            return null;
+        }
+
+        @Override
+        public Object getAttribute(String name) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "getAttribute({0})", name);
+            }
+            return attributes.get(name);
+        }
+
+        @Override
+        public Enumeration<String> getAttributeNames() {
+            LOG.log(Level.INFO, "getAttributeNames()");
+            return Collections.enumeration(attributes.keySet());
+        }
+
+        @Override
+        public String getCharacterEncoding() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getCharacterEncoding()");
+            return null;
+        }
+
+        @Override
+        public int getContentLength() {
+            LOG.log(Level.INFO, "getContentLength()");
+            return 0;
+        }
+
+        @Override
+        public String getContentType() {
+            LOG.log(Level.INFO, "getContentType()");
+            return requestHeaders.get("Content-Type");
+        }
+
+        @Override
+        public DispatcherType getDispatcherType() {
+            LOG.log(Level.INFO, "getDispatcherType()");
+            return websocket.getRequestProperty("dispatcherType", DispatcherType.class);
+        }
+
+        @Override
+        public ServletInputStream getInputStream() throws IOException {
+            return new ServletInputStream() {
+                @Override
+                public int read() throws IOException {
+                    return in.read();
+                }
+
+                @Override
+                public int read(byte[] b, int off, int len) throws IOException {
+                    return in.read(b, off, len);
+                }
+            };
+        }
+
+        @Override
+        public String getLocalAddr() {
+            LOG.log(Level.INFO, "getLocalAddr()");
+            return websocket.getRequestProperty("localAddr", String.class);
+        }
+
+        @Override
+        public String getLocalName() {
+            LOG.log(Level.INFO, "getLocalName()");
+            return websocket.getRequestProperty("localName", String.class);
+        }
+
+        @Override
+        public int getLocalPort() {
+            LOG.log(Level.INFO, "getLocalPort()");
+            return websocket.getRequestProperty("localPort", int.class);
+        }
+
+        @Override
+        public Locale getLocale() {
+            LOG.log(Level.INFO, "getLocale()");
+            return websocket.getRequestProperty("locale", Locale.class);
+        }
+
+        @Override
+        public Enumeration<Locale> getLocales() {
+            LOG.log(Level.INFO, "getLocales()");
+            return CastUtils.cast(websocket.getRequestProperty("locales", Enumeration.class));
+        }
+
+        @Override
+        public String getParameter(String name) {
+            // TODO Auto-generated method stub
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "getParameter({0})", name);
+            }
+            return null;
+        }
+
+        @Override
+        public Map<String, String[]> getParameterMap() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getParameterMap()");
+            return null;
+        }
+
+        @Override
+        public Enumeration<String> getParameterNames() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getParameterNames()");
+            return null;
+        }
+
+        @Override
+        public String[] getParameterValues(String name) {
+            // TODO Auto-generated method stub
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "getParameterValues({0})", name);
+            }
+            return null;
+        }
+
+        @Override
+        public String getProtocol() {
+            LOG.log(Level.INFO, "getProtocol");
+            return websocket.getRequestProperty("protocol", String.class);
+        }
+
+        @Override
+        public BufferedReader getReader() throws IOException {
+            LOG.log(Level.INFO, "getReader");
+            return new BufferedReader(new InputStreamReader(in, "utf-8"));
+        }
+
+        @Override
+        public String getRealPath(String path) {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getRealPath");
+            return null;
+        }
+
+        @Override
+        public String getRemoteAddr() {
+            LOG.log(Level.INFO, "getRemoteAddr");
+            return websocket.getRequestProperty("remoteAddr", String.class);
+        }
+
+        @Override
+        public String getRemoteHost() {
+            LOG.log(Level.INFO, "getRemoteHost");
+            return websocket.getRequestProperty("remoteHost", String.class);
+        }
+
+        @Override
+        public int getRemotePort() {
+            LOG.log(Level.INFO, "getRemotePort");
+            return websocket.getRequestProperty("remotePort", int.class);
+        }
+
+        @Override
+        public RequestDispatcher getRequestDispatcher(String path) {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getRequestDispatcher");
+            return null;
+        }
+
+        @Override
+        public String getScheme() {
+            LOG.log(Level.INFO, "getScheme");
+            return websocket.getRequestProperty("scheme", String.class);
+        }
+
+        @Override
+        public String getServerName() {
+            return websocket.getRequestProperty("serverName", String.class);
+        }
+
+        @Override
+        public int getServerPort() {
+            LOG.log(Level.INFO, "getServerPort");
+            return websocket.getRequestProperty("serverPoart", int.class);
+        }
+
+        @Override
+        public ServletContext getServletContext() {
+            LOG.log(Level.INFO, "getServletContext");
+            return context;
+        }
+
+        @Override
+        public boolean isAsyncStarted() {
+            LOG.log(Level.INFO, "isAsyncStarted");
+            return false;
+        }
+
+        @Override
+        public boolean isAsyncSupported() {
+            LOG.log(Level.INFO, "isAsyncSupported");
+            return false;
+        }
+
+        @Override
+        public boolean isSecure() {
+            LOG.log(Level.INFO, "isSecure");
+            return websocket.getRequestProperty("secure", boolean.class);
+        }
+
+        @Override
+        public void removeAttribute(String name) {
+            LOG.log(Level.INFO, "removeAttribute");
+            attributes.remove(name);
+        }
+
+        @Override
+        public void setAttribute(String name, Object o) {
+            LOG.log(Level.INFO, "setAttribute");
+            attributes.put(name,  o);
+        }
+
+        @Override
+        public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
+            LOG.log(Level.INFO, "setCharacterEncoding");
+            // ignore as we stick to utf-8.
+        }
+
+        @Override
+        public AsyncContext startAsync() {
+            LOG.log(Level.INFO, "startAsync");
+            return null;
+        }
+
+        @Override
+        public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "startAsync");
+            return null;
+        }
+
+        @Override
+        public boolean authenticate(HttpServletResponse servletResponse) throws IOException, ServletException {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "authenticate");
+            return false;
+        }
+
+        @Override
+        public String getAuthType() {
+            LOG.log(Level.INFO, "getAuthType");
+            return websocket.getRequestProperty("authType", String.class);
+        }
+
+        @Override
+        public String getContextPath() {
+            LOG.log(Level.INFO, "getContextPath");
+            return websocket.getRequestProperty("contextPath", String.class);
+        }
+
+        @Override
+        public Cookie[] getCookies() {
+            LOG.log(Level.INFO, "getCookies");
+            return null;
+        }
+
+        @Override
+        public long getDateHeader(String name) {
+            LOG.log(Level.INFO, "getDateHeader");
+            return 0;
+        }
+
+        @Override
+        public String getHeader(String name) {
+            LOG.log(Level.INFO, "getHeader");
+            return requestHeaders.get(name);
+        }
+
+        @Override
+        public Enumeration<String> getHeaderNames() {
+            LOG.log(Level.INFO, "getHeaderNames");
+            return Collections.enumeration(requestHeaders.keySet());
+        }
+
+        @Override
+        public Enumeration<String> getHeaders(String name) {
+            LOG.log(Level.INFO, "getHeaders");
+            // our protocol assumes no multiple headers
+            return Collections.enumeration(Arrays.asList(requestHeaders.get(name)));
+        }
+
+        @Override
+        public int getIntHeader(String name) {
+            LOG.log(Level.INFO, "getIntHeader");
+            String v = requestHeaders.get(name);
+            return v == null ? -1 : Integer.parseInt(v);
+        }
+
+        @Override
+        public String getMethod() {
+            LOG.log(Level.INFO, "getMethod");
+            return requestHeaders.get(METHOD_KEY);
+        }
+
+        @Override
+        public Part getPart(String name) throws IOException, ServletException {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getPart");
+            return null;
+        }
+
+        @Override
+        public Collection<Part> getParts() throws IOException, ServletException {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getParts");
+            return null;
+        }
+
+        @Override
+        public String getPathInfo() {
+            LOG.log(Level.INFO, "getPathInfo");
+            String uri = requestHeaders.get("$uri");
+            String servletpath = websocket.getRequestProperty("servletPath", String.class);
+            //TODO remove the query string part
+            //REVISIT may cache this value in requstHeaders?
+            return uri.substring(servletpath.length());
+        }
+
+        @Override
+        public String getPathTranslated() {
+            LOG.log(Level.INFO, "getPathTranslated");
+            String path = getPathInfo();
+            String opathtrans = websocket.getRequestProperty("pathTranslated", String.class);
+            String opathinfo = websocket.getRequestProperty("pathInfo", String.class);
+            int pos = opathtrans.indexOf(opathinfo);
+            //REVISIT may cache this value in requstHeaders?
+            return new StringBuilder().append(opathtrans.substring(0, pos)).append(path).toString();
+        }
+
+        @Override
+        public String getQueryString() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getQueryString");
+            return null;
+        }
+
+        @Override
+        public String getRemoteUser() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getRemoteUser");
+            return null;
+        }
+
+        @Override
+        public String getRequestURI() {
+            LOG.log(Level.INFO, "getRequestURI");
+            return requestHeaders.get(URI_KEY);
+        }
+
+        @Override
+        public StringBuffer getRequestURL() {
+            LOG.log(Level.INFO, "getRequestURL");
+            String url = websocket.getRequestProperty("requestURL", String.class);
+            String ouri = websocket.getRequestProperty("requestURI", String.class);
+            StringBuffer sb = new StringBuffer();
+            String uri = getRequestURI();
+            //REVISIT the way to reject the requeist uri that does not match the original request
+            if (!uri.startsWith(ouri)) {
+                sb.append(url).append("invalid").append(uri);
+            } else {
+                sb.append(url).append(uri.substring(ouri.length()));
+            }
+            
+            return sb;
+        }
+
+        @Override
+        public String getRequestedSessionId() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getRequestedSessionId");
+            return null;
+        }
+
+        @Override
+        public String getServletPath() {
+            LOG.log(Level.INFO, "getServletPath");
+            return websocket.getRequestProperty("servletPath", String.class);
+        }
+
+        @Override
+        public HttpSession getSession() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getSession");
+            return null;
+        }
+
+        @Override
+        public HttpSession getSession(boolean create) {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getSession");
+            return null;
+        }
+
+        @Override
+        public Principal getUserPrincipal() {
+            LOG.log(Level.INFO, "getUserPrincipal");
+            return websocket.getRequestProperty("userPrincipal", Principal.class);
+        }
+
+        @Override
+        public boolean isRequestedSessionIdFromCookie() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "isRequestedSessionIdFromCookie");
+            return false;
+        }
+
+        @Override
+        public boolean isRequestedSessionIdFromURL() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "isRequestedSessionIdFromURL");
+            return false;
+        }
+
+        @Override
+        public boolean isRequestedSessionIdFromUrl() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "isRequestedSessionIdFromUrl");
+            return false;
+        }
+
+        @Override
+        public boolean isRequestedSessionIdValid() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "isRequestedSessionIdValid");
+            return false;
+        }
+
+        @Override
+        public boolean isUserInRole(String role) {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "isUserInRole");
+            return false;
+        }
+
+        @Override
+        public void login(String username, String password) throws ServletException {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "login");
+            
+        }
+
+        @Override
+        public void logout() throws ServletException {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "logout");
+            
+        }
+    }
+
+    //TODO need to make the header setting to be written to the body (as symmetric to the request behavior)
+    static class WebSocketVirtualServletResponse implements HttpServletResponse {
+        private JettyWebSocket websocket;
+        private Map<String, String> responseHeaders;
+        private boolean flushed;
+
+        public WebSocketVirtualServletResponse(JettyWebSocket websocket) {
+            this.websocket = websocket;
+            this.responseHeaders = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+        }
+
+        @Override
+        public void flushBuffer() throws IOException {
+            LOG.log(Level.INFO, "flushBuffer()");
+            if (!flushed) {
+                //REVISIT this mechanism to determine if the headers have been flushed
+                if (responseHeaders.get(FLUSHED_KEY) == null) {
+                    byte[] data = buildResponse(responseHeaders, null, 0, 0);
+                    websocket.write(data, 0, data.length);
+                    responseHeaders.put(FLUSHED_KEY, "true");
+                }
+                flushed = true;
+            }
+        }
+
+        @Override
+        public int getBufferSize() {
+            LOG.log(Level.INFO, "getBufferSize()");
+            return 0;
+        }
+
+        @Override
+        public String getCharacterEncoding() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getCharacterEncoding()");
+            return null;
+        }
+
+        @Override
+        public String getContentType() {
+            LOG.log(Level.INFO, "getContentType()");
+            return responseHeaders.get("Content-Type");
+        }
+
+        @Override
+        public Locale getLocale() {
+            // TODO Auto-generated method stub
+            LOG.log(Level.INFO, "getLocale");
+            return null;
+        }
+
+        @Override
+        public ServletOutputStream getOutputStream() throws IOException {
+            LOG.log(Level.INFO, "getOutputStream()");
+            return websocket.getServletOutputStream(responseHeaders);
+        }
+
+        @Override
+        public PrintWriter getWriter() throws IOException {
+            LOG.log(Level.INFO, "getWriter()");
+            return new PrintWriter(websocket.getOutputStream(responseHeaders));
+        }
+
+        @Override
+        public boolean isCommitted() {
+            return false;
+        }
+
+        @Override
+        public void reset() {
+        }
+
+        @Override
+        public void resetBuffer() {
+            LOG.log(Level.INFO, "resetBuffer()");
+        }
+
+        @Override
+        public void setBufferSize(int size) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setBufferSize({0})", size);
+            }
+        }
+
+        @Override
+        public void setCharacterEncoding(String charset) {
+            // TODO 
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setCharacterEncoding({0})", charset);
+            }
+        }
+
+        @Override
+        public void setContentLength(int len) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setContentLength({0})", len);
+            }
+            responseHeaders.put("Content-Length", Integer.toString(len));
+        }
+
+        @Override
+        public void setContentType(String type) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setContentType({0})", type);
+            }
+            responseHeaders.put("Content-Type", type);
+        }
+
+        @Override
+        public void setLocale(Locale loc) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setLocale({0})", loc);
+            }
+        }
+
+        @Override
+        public void addCookie(Cookie cookie) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "addCookie({0})", cookie);
+            }
+        }
+
+        @Override
+        public void addDateHeader(String name, long date) {
+            // TODO
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "addDateHeader({0}, {1})", new Object[]{name, date});
+            }
+        }
+
+        @Override
+        public void addHeader(String name, String value) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "addHeader({0}, {1})", new Object[]{name, value});
+            }
+            responseHeaders.put(name, value);
+        }
+
+        @Override
+        public void addIntHeader(String name, int value) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "addIntHeader({0}, {1})", new Object[]{name, value});
+            }
+            responseHeaders.put(name, Integer.toString(value));
+        }
+
+        @Override
+        public boolean containsHeader(String name) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "containsHeader({0})", name);
+            }
+            return responseHeaders.containsKey(name);
+        }
+
+        @Override
+        public String encodeRedirectURL(String url) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "encodeRedirectURL({0})", url);
+            }
+            return null;
+        }
+
+        @Override
+        public String encodeRedirectUrl(String url) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "encodeRedirectUrl({0})", url);
+            }
+            return null;
+        }
+
+        @Override
+        public String encodeURL(String url) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "encodeURL({0})", url);
+            }
+            return null;
+        }
+
+        @Override
+        public String encodeUrl(String url) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "encodeUrl({0})", url);
+            }
+            return null;
+        }
+
+        @Override
+        public String getHeader(String name) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "getHeader({0})", name);
+            }
+            return null;
+        }
+
+        @Override
+        public Collection<String> getHeaderNames() {
+            LOG.log(Level.INFO, "getHeaderNames()");
+            return null;
+        }
+
+        @Override
+        public Collection<String> getHeaders(String name) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "getHeaders({0})", name);
+            }
+            return null;
+        }
+
+        @Override
+        public int getStatus() {
+            LOG.log(Level.INFO, "getStatus()");
+            String v = responseHeaders.get(SC_KEY);
+            return v == null ? 200 : Integer.parseInt(v);
+        }
+
+        @Override
+        public void sendError(int sc) throws IOException {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "sendError{0}", sc);
+            }
+            responseHeaders.put(SC_KEY, Integer.toString(sc));
+        }
+
+        @Override
+        public void sendError(int sc, String msg) throws IOException {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "sendError({0}, {1})", new Object[]{sc, msg});
+            }
+            responseHeaders.put(SC_KEY, Integer.toString(sc));
+            responseHeaders.put(SM_KEY, msg);
+        }
+
+        @Override
+        public void sendRedirect(String location) throws IOException {
+            // TODO Auto-generated method stub
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "sendRedirect({0})", location);
+            }
+        }
+
+        @Override
+        public void setDateHeader(String name, long date) {
+            // ignore
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setDateHeader({0}, {1})", new Object[]{name, date});
+            }
+        }
+
+        @Override
+        public void setHeader(String name, String value) {
+            // TODO Auto-generated method stub
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setHeader({0}, {1})", new Object[]{name, value});
+            }
+        }
+
+        @Override
+        public void setIntHeader(String name, int value) {
+            // TODO Auto-generated method stub
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setIntHeader({0}, {1})", new Object[]{name, value});
+            }
+        }
+
+        @Override
+        public void setStatus(int sc) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setStatus({0})", sc);
+            }
+            responseHeaders.put(SC_KEY, Integer.toString(sc));
+        }
+
+        @Override
+        public void setStatus(int sc, String sm) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.log(Level.INFO, "setStatus({0}, {1})", new Object[]{sc, sm});
+            }
+            responseHeaders.put(SC_KEY, Integer.toString(sc));
+            responseHeaders.put(SM_KEY, sm);
+        }
+    }
+
+    /*
+     * We accept only a restricted syntax as we have the syntax in our control.
+     * Do not allow multiline or line-wrapped headers.
+     * Do not allow charset other than utf-8. (although i would have preferred iso-8859-1 ;-)
+     */
+    private static Map<String, String> readHeaders(InputStream in) throws IOException {
+        Map<String, String> headers = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+        // read the request line
+        String line = readLine(in);
+        int del = line.indexOf(' ');
+        if (del < 0) {
+            throw new IOException("invalid request: " + line);
+        }
+        headers.put(METHOD_KEY, line.substring(0, del).trim());
+        headers.put(URI_KEY, line.substring(del + 1).trim());
+        
+        // read headers
+        while ((line = readLine(in)) != null) {
+            if (line.length() > 0) {
+                del = line.indexOf(':');
+                if (del < 0) {
+                    headers.put(line.trim(), "");
+                } else {
+                    headers.put(line.substring(0, del).trim(), line.substring(del + 1).trim());
+                }
+            }
+        }
+
+        return headers;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T getValue(Map<String, Object> properties, String name, Class<T> cls) {
+        return (T)properties.get(name);
+    }
+    
+
+    ///// this is copied from AttachmentDeserializer with a minor change. think about putting this method to IOUtils
+    private static String readLine(InputStream in) throws IOException {
+        StringBuilder buffer = new StringBuilder(128);
+
+        int c;
+
+        while ((c = in.read()) != -1) {
+            // a linefeed is a terminator, always.
+            if (c == '\n') {
+                break;
+            } else if (c == '\r') {
+                //just ignore the CR.  The next character SHOULD be an NL.  If not, we're
+                //just going to discard this
+                continue;
+            } else {
+                // just add to the buffer
+                buffer.append((char)c);
+            }
+        }
+
+        // no characters found...this was either an eof or a null line.
+        if (buffer.length() == 0) {
+            return null;
+        }
+
+        return buffer.toString();
+    }
+    ///// END
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketDestination.java
----------------------------------------------------------------------
diff --git a/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketDestination.java b/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketDestination.java
new file mode 100644
index 0000000..f849713
--- /dev/null
+++ b/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketDestination.java
@@ -0,0 +1,66 @@
+/**
+ * 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.transport.websocket.jetty;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.transport.http.DestinationRegistry;
+import org.apache.cxf.transport.http_jetty.JettyHTTPDestination;
+import org.apache.cxf.transport.http_jetty.JettyHTTPHandler;
+import org.apache.cxf.transport.http_jetty.JettyHTTPServerEngineFactory;
+
+/**
+ * 
+ */
+public class JettyWebSocketDestination extends JettyHTTPDestination {
+
+    public JettyWebSocketDestination(Bus bus, DestinationRegistry registry, EndpointInfo ei,
+                                     JettyHTTPServerEngineFactory serverEngineFactory) throws IOException {
+        super(bus, registry, ei, serverEngineFactory);
+    }
+
+    @Override
+    protected String getAddress(EndpointInfo endpointInfo) {
+        String address = endpointInfo.getAddress();
+        if (address.startsWith("ws")) {
+            address = "http" + address.substring(2);
+        }
+        return address;
+    }
+
+
+    @Override
+    protected String getBasePath(String contextPath) throws IOException {
+        if (StringUtils.isEmpty(endpointInfo.getAddress())) {
+            return "";
+        }
+        return new URL(getAddress(endpointInfo)).getPath();
+    }
+    
+    @Override
+    protected JettyHTTPHandler createJettyHTTPHandler(JettyHTTPDestination jhd, boolean cmExact) {
+        return new JettyWebSocketHandler(jhd, cmExact);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketHandler.java
----------------------------------------------------------------------
diff --git a/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketHandler.java b/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketHandler.java
new file mode 100644
index 0000000..be09dce
--- /dev/null
+++ b/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketHandler.java
@@ -0,0 +1,63 @@
+/**
+ * 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.transport.websocket.jetty;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.cxf.transport.http_jetty.JettyHTTPDestination;
+import org.apache.cxf.transport.http_jetty.JettyHTTPHandler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.websocket.WebSocket;
+import org.eclipse.jetty.websocket.WebSocketFactory;
+
+/**
+ * The extended version of JettyHTTPHandler that can support websocket.
+ */
+class JettyWebSocketHandler extends JettyHTTPHandler implements WebSocketFactory.Acceptor {
+    private JettyWebSocketManager webSocketManager;
+
+    public JettyWebSocketHandler(JettyHTTPDestination jhd, boolean cmExact) {
+        super(jhd, cmExact);
+        webSocketManager = new JettyWebSocketManager();
+        webSocketManager.init(this, jhd);
+    }
+
+    public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
+        return new JettyWebSocket(webSocketManager, request, protocol);
+    }
+    
+    @Override
+    public void handle(String target, Request baseRequest, HttpServletRequest request,
+                       HttpServletResponse response) throws IOException, ServletException {
+        // only switch to websocket if websocket is enabled for this destination 
+        if (webSocketManager.acceptWebSocket(request, response)) {
+            baseRequest.setHandled(true);
+        } else {
+            super.handle(target, baseRequest, request, response);
+        }
+    }
+
+    public boolean checkOrigin(HttpServletRequest request, String protocol) {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketManager.java
----------------------------------------------------------------------
diff --git a/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketManager.java b/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketManager.java
new file mode 100644
index 0000000..139b1a6
--- /dev/null
+++ b/rt/transports/websocket/src/main/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketManager.java
@@ -0,0 +1,114 @@
+/**
+ * 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.transport.websocket.jetty;
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.cxf.transport.http.AbstractHTTPDestination;
+import org.apache.cxf.transport.http_jetty.JettyHTTPDestination;
+import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
+import org.eclipse.jetty.websocket.WebSocketFactory;
+import org.eclipse.jetty.websocket.WebSocketFactory.Acceptor;
+
+/**
+ * 
+ */
+public class JettyWebSocketManager {
+    private WebSocketFactory webSocketFactory;
+    
+    // either servlet is set or destination + servletContext are set
+    private CXFNonSpringServlet servlet;
+    private AbstractHTTPDestination destination;
+    private ServletContext servletContext;
+
+    public void init(JettyWebSocketHandler handler, JettyHTTPDestination dest) {
+        this.destination = dest;
+        //TODO customize websocket factory configuration options when using the destination.
+        
+        webSocketFactory = new WebSocketFactory((Acceptor)handler, 8192);
+    }
+
+    public void init(CXFNonSpringServlet srvlt, ServletConfig sc) throws ServletException {
+        this.servlet = srvlt;
+        try {
+            
+            String bs = srvlt.getInitParameter("bufferSize");
+            
+            webSocketFactory = new WebSocketFactory((Acceptor)srvlt, bs == null ? 8192 : Integer.parseInt(bs));
+            webSocketFactory.start();
+        
+            String max = srvlt.getInitParameter("maxIdleTime");
+            if (max != null) {
+                webSocketFactory.setMaxIdleTime(Integer.parseInt(max));
+            }
+            max = srvlt.getInitParameter("maxTextMessageSize");
+            if (max != null) {
+                webSocketFactory.setMaxTextMessageSize(Integer.parseInt(max));
+            }
+            max = srvlt.getInitParameter("maxBinaryMessageSize");
+            if (max != null) {
+                webSocketFactory.setMaxBinaryMessageSize(Integer.parseInt(max));
+            }
+        } catch (Exception e) {
+            throw e instanceof ServletException ? (ServletException)e : new ServletException(e);
+        }
+    }
+    
+    void setServletContext(ServletContext servletContext) {
+        this.servletContext = servletContext;
+    }
+
+    public void destroy() {
+        try {
+            webSocketFactory.stop();
+        } catch (Exception e) {
+            // ignore
+        }
+    }
+
+    public boolean acceptWebSocket(ServletRequest req, ServletResponse res) throws IOException {
+        try {
+            HttpServletRequest request = (HttpServletRequest) req;
+            HttpServletResponse response = (HttpServletResponse) res;
+            if (webSocketFactory.acceptWebSocket(request, response) || response.isCommitted()) {
+                return true;
+            }
+        } catch (ClassCastException e) {
+            // ignore
+        }
+        return false;
+    }
+
+    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+        if (destination != null) {
+            destination.invoke(null, servletContext, request, response);
+        } else if (servlet != null) {
+            ((CXFJettyWebSocketServletService)servlet).serviceInternal(request, response);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/rt/transports/websocket/src/main/resources/META-INF/cxf/bus-extensions.txt
----------------------------------------------------------------------
diff --git a/rt/transports/websocket/src/main/resources/META-INF/cxf/bus-extensions.txt b/rt/transports/websocket/src/main/resources/META-INF/cxf/bus-extensions.txt
new file mode 100644
index 0000000..133e3b2
--- /dev/null
+++ b/rt/transports/websocket/src/main/resources/META-INF/cxf/bus-extensions.txt
@@ -0,0 +1,4 @@
+org.apache.cxf.transport.websocket.WebSocketTransportFactory::true
+
+
+

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/rt/transports/websocket/src/test/java/org/apache/cxf/transport/websocket/WebSocketTransportFactoryTest.java
----------------------------------------------------------------------
diff --git a/rt/transports/websocket/src/test/java/org/apache/cxf/transport/websocket/WebSocketTransportFactoryTest.java b/rt/transports/websocket/src/test/java/org/apache/cxf/transport/websocket/WebSocketTransportFactoryTest.java
new file mode 100644
index 0000000..d53339a
--- /dev/null
+++ b/rt/transports/websocket/src/test/java/org/apache/cxf/transport/websocket/WebSocketTransportFactoryTest.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 org.apache.cxf.transport.websocket;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.transport.Destination;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class WebSocketTransportFactoryTest extends Assert {
+
+    @Test
+    public void testGetDestination() throws Exception {
+        Bus bus = BusFactory.getDefaultBus();
+        EndpointInfo ei = new EndpointInfo();
+        ei.setAddress("ws://localhost:8888/bar/foo");
+        WebSocketTransportFactory factory = bus.getExtension(WebSocketTransportFactory.class);
+        assertNotNull(factory);
+        Destination dest = factory.getDestination(ei, bus);
+        assertNotNull(dest);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/rt/transports/websocket/src/test/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketManagerTest.java
----------------------------------------------------------------------
diff --git a/rt/transports/websocket/src/test/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketManagerTest.java b/rt/transports/websocket/src/test/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketManagerTest.java
new file mode 100644
index 0000000..a74b1f1
--- /dev/null
+++ b/rt/transports/websocket/src/test/java/org/apache/cxf/transport/websocket/jetty/JettyWebSocketManagerTest.java
@@ -0,0 +1,84 @@
+/**
+ * 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.transport.websocket.jetty;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.cxf.transport.http_jetty.JettyHTTPDestination;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * 
+ */
+public class JettyWebSocketManagerTest extends Assert {
+    private IMocksControl control;
+
+    @Before
+    public void setUp() {
+        control = EasyMock.createNiceControl();
+    }
+    
+    @Test
+    public void testServiceUsingDestination() throws Exception {
+        JettyWebSocketManager jwsm = new JettyWebSocketManager();
+        
+        JettyWebSocketHandler handler = control.createMock(JettyWebSocketHandler.class);
+        JettyHTTPDestination dest = control.createMock(JettyHTTPDestination.class);
+                
+        HttpServletRequest request = control.createMock(HttpServletRequest.class);
+        HttpServletResponse response = control.createMock(HttpServletResponse.class);
+        
+        dest.invoke(EasyMock.isNull(ServletConfig.class), EasyMock.isNull(ServletContext.class), 
+                    EasyMock.eq(request), EasyMock.eq(response));
+        EasyMock.expectLastCall();
+        control.replay();
+        jwsm.init(handler, dest);
+        
+        jwsm.service(request, response);
+        control.verify();
+    }
+
+    @Test
+    public void testServiceUsingServlet() throws Exception {
+        JettyWebSocketManager jwsm = new JettyWebSocketManager();
+        
+        HttpServletRequest request = control.createMock(HttpServletRequest.class);
+        HttpServletResponse response = control.createMock(HttpServletResponse.class);
+        
+        CXFNonSpringJettyWebSocketServlet srvlt = control.createMock(CXFNonSpringJettyWebSocketServlet.class);
+        ServletConfig sc = control.createMock(ServletConfig.class);
+
+        srvlt.serviceInternal(EasyMock.eq(request), EasyMock.eq(response));
+        EasyMock.expectLastCall();
+        control.replay();
+        jwsm.init(srvlt, sc);
+        
+        jwsm.service(request, response);
+        control.verify();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/systests/jaxrs/pom.xml
----------------------------------------------------------------------
diff --git a/systests/jaxrs/pom.xml b/systests/jaxrs/pom.xml
index f7fe056..b51e50e 100644
--- a/systests/jaxrs/pom.xml
+++ b/systests/jaxrs/pom.xml
@@ -170,6 +170,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-websocket</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
             <artifactId>cxf-rt-features-clustering</artifactId>
             <version>${project.version}</version>
         </dependency>

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/BookServerWebSocket.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/BookServerWebSocket.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/BookServerWebSocket.java
index e5275df..e9bd712 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/BookServerWebSocket.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/BookServerWebSocket.java
@@ -19,32 +19,19 @@
 
 package org.apache.cxf.systest.jaxrs.websocket;
 
-import java.util.Collections;
-import java.util.Map;
-
 import org.apache.cxf.Bus;
 import org.apache.cxf.BusFactory;
 import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
 import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
 import org.apache.cxf.systest.jaxrs.BookStorePerRequest;
 import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
-import org.apache.cxf.transport.http_jetty.JettyHTTPDestination;
     
 public class BookServerWebSocket extends AbstractBusTestServerBase {
     public static final String PORT = allocatePort(BookServerWebSocket.class);
      
     org.apache.cxf.endpoint.Server server;
-    private Map< ? extends String, ? extends Object > properties;
     
     public BookServerWebSocket() {
-        this(Collections.< String, Object >emptyMap());
-    }
-    
-    /**
-     * Allow to specified custom contextual properties to be passed to factory bean
-     */
-    public BookServerWebSocket(final Map< ? extends String, ? extends Object > properties) {
-        this.properties = properties;
     }
     
     protected void run() {
@@ -55,10 +42,9 @@ public class BookServerWebSocket extends AbstractBusTestServerBase {
         sf.setResourceClasses(BookStoreWebSocket.class, BookStorePerRequest.class);
         sf.setResourceProvider(BookStoreWebSocket.class,
                                new SingletonResourceProvider(new BookStoreWebSocket(), true));
-        sf.setAddress("http://localhost:" + PORT + "/");
+        sf.setAddress("ws://localhost:" + PORT + "/");
         server = sf.create();
-        ((JettyHTTPDestination)server.getDestination())
-            .setEnableWebSocket(Boolean.parseBoolean((String)properties.get("enableWebSocket")));
+
         BusFactory.setDefaultBus(null);
         BusFactory.setThreadDefaultBus(null);
     }

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketSpringTest.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketSpringTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketSpringTest.java
new file mode 100644
index 0000000..56e6262
--- /dev/null
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketSpringTest.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 org.apache.cxf.systest.jaxrs.websocket;
+
+import org.junit.BeforeClass;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * JAXRSClientServerWebSocket test with jaxrs:server using the embedded jetty server.
+ */
+public class JAXRSClientServerWebSocketSpringTest extends JAXRSClientServerWebSocketTest {
+    public static final String PORT = BookServerWebSocket.PORT;
+    @BeforeClass
+    public static void startServers() throws Exception {
+
+        @SuppressWarnings("unused")
+        ApplicationContext appctxt = 
+            new ClassPathXmlApplicationContext(
+                JAXRSClientServerWebSocketSpringTest.class.getResource(
+                    "/jaxrs_websocket/beans-embedded.xml").toString());
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketSpringWebAppTest.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketSpringWebAppTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketSpringWebAppTest.java
new file mode 100644
index 0000000..4522d99
--- /dev/null
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketSpringWebAppTest.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.jaxrs.websocket;
+
+import java.net.URISyntaxException;
+
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.handler.DefaultHandler;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.nio.SelectChannelConnector;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+import org.junit.BeforeClass;
+
+/**
+ * JAXRSClientServerWebSocket test with jaxrs:server using the jetty webapp server.
+ */
+public class JAXRSClientServerWebSocketSpringWebAppTest extends JAXRSClientServerWebSocketTest {
+    public static final String PORT = BookServerWebSocket.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        org.eclipse.jetty.server.Server server = new org.eclipse.jetty.server.Server();
+
+        SelectChannelConnector connector = new SelectChannelConnector();
+        connector.setPort(Integer.parseInt(PORT));
+        server.setConnectors(new Connector[] {connector});
+
+        WebAppContext webappcontext = new WebAppContext();
+        String contextPath = null;
+        try {
+            contextPath = JAXRSClientServerWebSocketSpringWebAppTest.class
+                .getResource("/jaxrs_websocket").toURI().getPath();
+        } catch (URISyntaxException e1) {
+            e1.printStackTrace();
+        }
+        webappcontext.setContextPath("/");
+
+        webappcontext.setWar(contextPath);
+        HandlerCollection handlers = new HandlerCollection();
+        handlers.setHandlers(new Handler[] {webappcontext, new DefaultHandler()});
+        server.setHandler(handlers);
+        server.start();
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketTest.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketTest.java
index 9688197..9a5aa8c 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketTest.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/websocket/JAXRSClientServerWebSocketTest.java
@@ -19,9 +19,7 @@
 
 package org.apache.cxf.systest.jaxrs.websocket;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
 import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
@@ -34,14 +32,11 @@ public class JAXRSClientServerWebSocketTest extends AbstractBusClientServerTestB
     
     @BeforeClass
     public static void startServers() throws Exception {
-        final Map< String, Object > properties = new HashMap< String, Object >();        
-        properties.put("enableWebSocket", "true");
-
         AbstractResourceInfo.clearAllMaps();
-        assertTrue("server did not launch correctly", launchServer(new BookServerWebSocket(properties)));
+        assertTrue("server did not launch correctly", launchServer(new BookServerWebSocket()));
         createStaticBus();
     }
-        
+    
     @Test
     public void testBookWithWebSocket() throws Exception {
         String address = "ws://localhost:" + PORT + "/web/bookstore";

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/systests/jaxrs/src/test/resources/jaxrs_websocket/WEB-INF/beans.xml
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/resources/jaxrs_websocket/WEB-INF/beans.xml b/systests/jaxrs/src/test/resources/jaxrs_websocket/WEB-INF/beans.xml
new file mode 100644
index 0000000..45701db
--- /dev/null
+++ b/systests/jaxrs/src/test/resources/jaxrs_websocket/WEB-INF/beans.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<!-- START SNIPPET: beans -->
+<beans xmlns="http://www.springframework.org/schema/beans" 
+   xmlns:http="http://cxf.apache.org/transports/http/configuration"
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" 
+   xmlns:jaxrs="http://cxf.apache.org/jaxrs" 
+   xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
+   xmlns:cxf="http://cxf.apache.org/core" 
+   xsi:schemaLocation="
+   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
+   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
+   http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
+   http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
+   http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd
+   http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">
+    <import resource="classpath:META-INF/cxf/cxf.xml"/>
+    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
+
+    <bean class="org.apache.cxf.systest.jaxrs.websocket.BookStoreWebSocket" id="serviceBean"/>
+
+    <jaxrs:server id="bookservice" address="/" transportId="http://cxf.apache.org/transports/websockt">
+        <jaxrs:serviceBeans>
+            <ref bean="serviceBean"/>
+        </jaxrs:serviceBeans>
+    </jaxrs:server>
+</beans>
+<!-- END SNIPPET: beans -->

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/systests/jaxrs/src/test/resources/jaxrs_websocket/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/resources/jaxrs_websocket/WEB-INF/web.xml b/systests/jaxrs/src/test/resources/jaxrs_websocket/WEB-INF/web.xml
new file mode 100644
index 0000000..7619cdf
--- /dev/null
+++ b/systests/jaxrs/src/test/resources/jaxrs_websocket/WEB-INF/web.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
+<!--
+        Licensed to the Apache Software Foundation (ASF) under one
+        or more contributor license agreements. See the NOTICE file
+        distributed with this work for additional information
+        regarding copyright ownership. The ASF licenses this file
+        to you under the Apache License, Version 2.0 (the
+        "License"); you may not use this file except in compliance
+        with the License. You may obtain a copy of the License at
+        
+        http://www.apache.org/licenses/LICENSE-2.0
+        
+        Unless required by applicable law or agreed to in writing,
+        software distributed under the License is distributed on an
+        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+        KIND, either express or implied. See the License for the
+        specific language governing permissions and limitations
+        under the License.
+-->
+<!-- START SNIPPET: webxml -->
+<web-app>
+    <context-param>
+        <param-name>contextConfigLocation</param-name>
+        <param-value>WEB-INF/beans.xml</param-value>
+    </context-param>
+    <listener>
+        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+    </listener>
+    <servlet>
+        <servlet-name>CXFJettyWebSocketServlet</servlet-name>
+        <display-name>CXF JettyWebSocketServlet</display-name>
+        <servlet-class>org.apache.cxf.transport.websocket.jetty.CXFJettyWebSocketServlet</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>CXFJettyWebSocketServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>
+<!-- END SNIPPET: webxml -->

http://git-wip-us.apache.org/repos/asf/cxf/blob/8fe4fc13/systests/jaxrs/src/test/resources/jaxrs_websocket/beans-embedded.xml
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/resources/jaxrs_websocket/beans-embedded.xml b/systests/jaxrs/src/test/resources/jaxrs_websocket/beans-embedded.xml
new file mode 100644
index 0000000..03c5c5a
--- /dev/null
+++ b/systests/jaxrs/src/test/resources/jaxrs_websocket/beans-embedded.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<!-- START SNIPPET: beans -->
+<beans xmlns="http://www.springframework.org/schema/beans" 
+   xmlns:http="http://cxf.apache.org/transports/http/configuration"
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" 
+   xmlns:jaxrs="http://cxf.apache.org/jaxrs" 
+   xmlns:cxf="http://cxf.apache.org/core" 
+   xsi:schemaLocation="
+   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
+   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
+   http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
+   http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
+   http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">
+    <import resource="classpath:META-INF/cxf/cxf.xml"/>
+    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
+
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
+        
+    <bean class="org.apache.cxf.systest.jaxrs.websocket.BookStoreWebSocket" id="serviceBean"/>
+
+    <jaxrs:server id="bookservice" address="ws://localhost:${testutil.ports.BookServerWebSocket}/">
+        <jaxrs:serviceBeans>
+            <ref bean="serviceBean"/>
+        </jaxrs:serviceBeans>
+    </jaxrs:server>
+</beans>
+<!-- END SNIPPET: beans -->


Mime
View raw message