org.waveprotocol.box.webclient.client.atmosphere.AtmosphereConnectionImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.waveprotocol.box.webclient.client.atmosphere.AtmosphereConnectionImpl.java

Source

/**
 * 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.waveprotocol.box.webclient.client.atmosphere;

import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.ScriptInjector;

/**
 * The wrapper implementation of the atmosphere javascript client.
 *
 * https://github.com/Atmosphere/atmosphere/wiki/jQuery.atmosphere.js-atmosphere
 * .js-API
 *
 * More info about transports
 * https://github.com/Atmosphere/atmosphere/wiki/Supported
 * -WebServers-and-Browsers
 *
 * It tries to use Server-Sent Events first and fallback transport to
 * long-polling. We ignore Websockets by now because they are the default
 * transport on WiAB and atmosphere is the fallback.
 *
 * http://stackoverflow.com/questions/9397528/server-sent-events-vs-polling
 *
 *
 * @author pablojan@gmail.com (Pablo Ojanguren)
 *
 */
public class AtmosphereConnectionImpl implements AtmosphereConnection {

    private static final class AtmosphereSocket extends JavaScriptObject {
        public static native AtmosphereSocket create(AtmosphereConnectionImpl impl, String urlBase) /*-{
                                                                                                        
                                                                                                    var client = $wnd.atmosphere;
                                                                                                        
                                                                                                    var atsocket = {
                                                                                                    request: null,
                                                                                                    socket: null };
                                                                                                        
                                                                                                    var connectionUrl = window.location.protocol + "//" +  $wnd.__websocket_address + "/";
                                                                                                        
                                                                                                    connectionUrl += 'atmosphere';
                                                                                                        
                                                                                                    //console.log("Connection URL is "+urlBase);
                                                                                                    atsocket.request = new client.AtmosphereRequest();
                                                                                                    atsocket.request.url = connectionUrl;
                                                                                                    atsocket.request.contenType = 'text/plain;charset=UTF-8';
                                                                                                    atsocket.request.transport = 'sse';
                                                                                                    atsocket.request.fallbackTransport = 'long-polling';
                                                                                                        
                                                                                                    atsocket.request.onOpen = $entry(function() {
                                                                                                    impl.@org.waveprotocol.box.webclient.client.atmosphere.AtmosphereConnectionImpl::onConnect()();
                                                                                                    });
                                                                                                        
                                                                                                    atsocket.request.onMessage =  $entry(function(response) {
                                                                                                        
                                                                                                    var r = response.responseBody;
                                                                                                        
                                                                                                    if (r.indexOf('|') == 0) {
                                                                                                        
                                                                                                    while (r.indexOf('|') == 0 && r.length > 1) {
                                                                                                        
                                                                                                    r = r.substring(1);
                                                                                                    var marker = r.indexOf('}|');
                                                                                                    impl.@org.waveprotocol.box.webclient.client.atmosphere.AtmosphereConnectionImpl::onMessage(Ljava/lang/String;)(r.substring(0, marker+1));
                                                                                                    r = r.substring(marker+1);
                                                                                                        
                                                                                                    }
                                                                                                        
                                                                                                    }
                                                                                                    else {
                                                                                                        
                                                                                                    impl.@org.waveprotocol.box.webclient.client.atmosphere.AtmosphereConnectionImpl::onMessage(Ljava/lang/String;)(r);
                                                                                                        
                                                                                                    }
                                                                                                        
                                                                                                    });
                                                                                                        
                                                                                                    atsocket.request.onClose = $entry(function(response) {
                                                                                                        
                                                                                                    client.util.info("Connection closed");
                                                                                                        
                                                                                                    impl.@org.waveprotocol.box.webclient.client.atmosphere.AtmosphereConnectionImpl::onDisconnect(Ljava/lang/String;)(response);
                                                                                                    });
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                    atsocket.request.onTransportFailure = function(errorMsg, request) {
                                                                                                        
                                                                                                    client.util.info(errorMsg);
                                                                                                        
                                                                                                    };
                                                                                                        
                                                                                                        
                                                                                                    atsocket.request.onReconnect = function(request, response) {
                                                                                                        
                                                                                                    client.util.info("Reconnected to the server");
                                                                                                        
                                                                                                    };
                                                                                                        
                                                                                                    atsocket.request.onError = function(response) {
                                                                                                        
                                                                                                    client.util.info("Unexpected Error");
                                                                                                        
                                                                                                    };
                                                                                                        
                                                                                                        
                                                                                                    return atsocket;
                                                                                                        
                                                                                                        
                                                                                                    }-*/;

        protected AtmosphereSocket() {
        }

        public native void close() /*-{
                                   this.socket.unsubscribe();
                                   }-*/;

        public native AtmosphereSocket connect() /*-{
                                                 this.socket = $wnd.atmosphere.subscribe(this.request);
                                                     
                                                 }-*/;

        public native void send(String data) /*-{
                                             this.socket.push(data);
                                             }-*/;
    }

    private final AtmosphereConnectionListener listener;
    private String urlBase;
    private AtmosphereConnectionState state;
    private AtmosphereSocket socket = null;

    public AtmosphereConnectionImpl(AtmosphereConnectionListener listener, String urlBase) {
        this.listener = listener;
        this.urlBase = urlBase;

    }

    @Override
    public void connect() {
        if (socket == null) {

            ScriptInjector.fromUrl("/atmosphere/atmosphere.js").setCallback(new Callback<Void, Exception>() {
                public void onFailure(Exception reason) {
                    throw new IllegalStateException("atmosphere.js load failed!");
                }

                public void onSuccess(Void result) {

                    socket = AtmosphereSocket.create(AtmosphereConnectionImpl.this, urlBase);
                    socket.connect();
                }
            }).setWindow(ScriptInjector.TOP_WINDOW).inject();
        } else {

            if (AtmosphereConnectionState.CLOSED.equals(this.state))
                socket.connect();

        }
    }

    @Override
    public void close() {
        if (!AtmosphereConnectionState.CLOSED.equals(this.state))
            socket.close();

    }

    @Override
    public void sendMessage(String message) {
        this.state = AtmosphereConnectionState.MESSAGE_PUBLISHED;
        socket.send(message);
    }

    @SuppressWarnings("unused")
    private void onConnect() {
        this.state = AtmosphereConnectionState.OPENED;
        listener.onConnect();
    }

    /**
     * This method is called when an Atmosphere onClose event happens:
     *
     * when an error occurs. when the server or a proxy closes the connection.
     * when an expected exception occurs. when the specified transport is not
     * supported or fail to connect.
     *
     * @param response
     *
     */
    @SuppressWarnings("unused")
    private void onDisconnect(String response) {
        this.state = AtmosphereConnectionState.CLOSED;
        listener.onDisconnect();
    }

    @SuppressWarnings("unused")
    private void onMessage(String message) {
        this.state = AtmosphereConnectionState.MESSAGE_RECEIVED;
        listener.onMessage(message);
    }

}