/* * Copyright 2014 cruxframework.org. * * Licensed 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.cruxframework.crux.core.client.websocket; import org.cruxframework.crux.core.client.collection.FastList; import org.cruxframework.crux.core.client.file.Blob; import com.google.gwt.core.client.JsArrayString; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.typedarrays.shared.ArrayBuffer; import com.google.gwt.typedarrays.shared.ArrayBufferView; /** * Implementation for HTML5 WebSocket API (http://www.w3.org/TR/2011/WD-websockets-20110419/) * @author Thiago da Rosa de Bustamante * */ public class WebSocket { private FastList<SocketMessageHandler> messageHandlers = new FastList<SocketMessageHandler>(); private FastList<SocketOpenHandler> openHandlers = new FastList<SocketOpenHandler>(); private FastList<SocketCloseHandler> closeHandlers = new FastList<SocketCloseHandler>(); private FastList<SocketErrorHandler> errorHandlers = new FastList<SocketErrorHandler>(); private WebSocketJS socketJS; private String url; private String protocol; private JsArrayString protocols; protected WebSocket(WebSocketJS socketJS) { defineSocketJS(socketJS); } public static final short CONNECTING = 0; public static final short OPEN = 1; public static final short CLOSING = 2; public static final short CLOSED = 3; public short getReadyState() { return socketJS.getReadyState(); } public double getBufferedAmount() { return socketJS.getBufferedAmount(); } public String getUrl() { return socketJS.getUrl(); } public String getProtocol() { return socketJS.getProtocol(); } public String getExtensions() { return socketJS.getExtensions(); } public void send(String data) { socketJS.send(data); } public void send(Blob data) { socketJS.send(data); } public void send(ArrayBuffer data) { socketJS.send(data); } public void send(ArrayBufferView data) { socketJS.send(data); } public void close() { socketJS.close(); } public void close(short code, String reason) { socketJS.close(code, reason); } public HandlerRegistration addMessageHandler(final SocketMessageHandler handler) { messageHandlers.add(handler); return new HandlerRegistration() { @Override public void removeHandler() { int index = messageHandlers.indexOf(handler); if (index >= 0) { messageHandlers.remove(index); } } }; } public HandlerRegistration addOpenHandler(final SocketOpenHandler handler) { openHandlers.add(handler); return new HandlerRegistration() { @Override public void removeHandler() { int index = openHandlers.indexOf(handler); if (index >= 0) { openHandlers.remove(index); } } }; } public HandlerRegistration addCloseHandler(final SocketCloseHandler handler) { closeHandlers.add(handler); return new HandlerRegistration() { @Override public void removeHandler() { int index = closeHandlers.indexOf(handler); if (index >= 0) { closeHandlers.remove(index); } } }; } public HandlerRegistration addErrorHandler(final SocketErrorHandler handler) { errorHandlers.add(handler); return new HandlerRegistration() { @Override public void removeHandler() { int index = errorHandlers.indexOf(handler); if (index >= 0) { errorHandlers.remove(index); } } }; } public void reconnect() { WebSocketJS webSocketJS; if(this.protocols != null) { webSocketJS = WebSocketJS.createSocket(url, protocols); } else if(this.protocol != null) { webSocketJS = WebSocketJS.createSocket(url, protocol); } else { webSocketJS = WebSocketJS.createSocket(url); } defineSocketJS(webSocketJS); } void fireMessageEvent(String message) { SocketMessageEvent event = new SocketMessageEvent(this, message); for (int i = 0; i < messageHandlers.size(); i++) { SocketMessageHandler handler = messageHandlers.get(i); handler.onMessage(event); } } void fireErrorEvent() { SocketErrorEvent event = new SocketErrorEvent(this); for (int i = 0; i < errorHandlers.size(); i++) { SocketErrorHandler handler = errorHandlers.get(i); handler.onError(event); } } void fireOpenEvent() { SocketOpenEvent event = new SocketOpenEvent(this); for (int i = 0; i < openHandlers.size(); i++) { SocketOpenHandler handler = openHandlers.get(i); handler.onOpen(event); } } void fireCloseEvent(boolean wasClean, short code, String reason) { SocketCloseEvent event = new SocketCloseEvent(this, wasClean, code, reason); for (int i = 0; i < closeHandlers.size(); i++) { SocketCloseHandler handler = closeHandlers.get(i); handler.onClose(event); } } public static native final boolean isSupported()/*-{ if ($wnd.WebSocket) { return true; } return false; }-*/; public static final WebSocket createIfSupported(String url) { if (isSupported()) { WebSocketJS webSocketJS = WebSocketJS.createSocket(url); WebSocket socket = new WebSocket(webSocketJS); socket.url = url; return socket; } return null; } public static final WebSocket createIfSupported(String url, String protocol) { if (isSupported()) { WebSocketJS webSocketJS = WebSocketJS.createSocket(url, protocol); WebSocket socket = new WebSocket(webSocketJS); socket.url = url; socket.protocol = protocol; return socket; } return null; } public static final WebSocket createIfSupported(String url, JsArrayString protocols) { if (isSupported()) { WebSocketJS webSocketJS = WebSocketJS.createSocket(url, protocols); WebSocket socket = new WebSocket(webSocketJS); socket.url = url; socket.protocols = protocols; return socket; } return null; } private void defineSocketJS(WebSocketJS socketJS) { if (this.socketJS != null) { removeOldHandlers(this.socketJS); } this.socketJS = socketJS; initializeSocketHandlers(this, socketJS); } private native void initializeSocketHandlers(WebSocket socket, WebSocketJS socketJS)/*-{ socketJS.onerror = function() { socket.@org.cruxframework.crux.core.client.websocket.WebSocket::fireErrorEvent()(); }; socketJS.onopen = function() { socket.@org.cruxframework.crux.core.client.websocket.WebSocket::fireOpenEvent()(); }; socketJS.onmessage = function(event) { socket.@org.cruxframework.crux.core.client.websocket.WebSocket::fireMessageEvent(Ljava/lang/String;)(event.data); }; socketJS.onclose = function(event) { socket.@org.cruxframework.crux.core.client.websocket.WebSocket::fireCloseEvent(ZSLjava/lang/String;)(event.wasClean, event.code, event.reason); }; }-*/; private native void removeOldHandlers(WebSocketJS socketJS)/*-{ socketJS.onerror = null; socketJS.onopen = null; socketJS.onmessage = null; socketJS.onclose = null; }-*/; }