com.emorym.android_pusher.Pusher.java Source code

Java tutorial

Introduction

Here is the source code for com.emorym.android_pusher.Pusher.java

Source

package com.emorym.android_pusher;

/*   Copyright (C) 2011 Emory Myers 
 * 
 *  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. 
 */

import static android.util.Log.DEBUG;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import de.roderick.weberknecht.WebSocketConnection;
import de.roderick.weberknecht.WebSocketEventHandler;
import de.roderick.weberknecht.WebSocketException;
import de.roderick.weberknecht.WebSocketMessage;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

public class Pusher {
    private static final String TAG = "Pusher";
    protected static final long WATCHDOG_SLEEP_TIME_MS = 5000;
    private final String VERSION = "1.8.3";
    private final String HOST = "ws.pusherapp.com";

    private final int WS_PORT = 80;
    private final int WSS_PORT = 443;

    private final String HTTP_PREFIX = "ws://";
    private final String HTTPS_PREFIX = "wss://";

    protected WebSocketConnection mWebSocket = null;
    private final Handler mHandler;
    private Thread mWatchdog; // handles reconnecting
    protected String mSocketId;
    private String mApplicationkey;
    private boolean mEncrypted;
    private boolean trustAllCerts;

    public final HashMap<String, Channel> channels = new HashMap<String, Channel>();
    public final Channel globalChannel = new Channel("pusher_global_channel");

    public Pusher(String application_key, boolean encrypted, boolean trustAllCertificates) {
        mApplicationkey = application_key;
        mEncrypted = encrypted;
        trustAllCerts = trustAllCertificates;
        mHandler = new PusherHandler(this);
        connect();
    }

    public Pusher(String application_key, boolean encrypted) {
        this(application_key, encrypted, false);
    }

    public Pusher(String application_key) {
        this(application_key, true);
    }

    @Deprecated
    public Pusher(Handler _mHandler, boolean encrypted) {
        // So we can get our messages back to whatever created this
        mHandler = _mHandler;
        mEncrypted = encrypted;
    }

    @Deprecated
    public Pusher(Handler _mHandler) {
        this(_mHandler, true);
    }

    public void disconnect() {
        try {
            mWatchdog.interrupt();
            mWatchdog = null;
            mWebSocket.close();
        } catch (WebSocketException e) {
            if (Log.isLoggable(TAG, DEBUG))
                Log.d(TAG, "Exception closing web socket", e);
        }
    }

    public Pusher bind(String event, PusherCallback callback) {
        globalChannel.bind(event, callback);

        return this;
    }

    public Pusher bindAll(PusherCallback callback) {
        globalChannel.bindAll(callback);

        return this;
    }

    public Pusher unbind(String event) {
        globalChannel.unbind(event);

        return this;
    }

    public Channel subscribe(String channelName) {
        Channel c = new Channel(channelName);

        if (mWebSocket != null && mWebSocket.isConnected()) {
            try {
                sendSubscribeMessage(c);
            } catch (Exception e) {
                if (Log.isLoggable(TAG, DEBUG))
                    Log.d(TAG, "Exception sending subscribe message", e);
            }
        }

        channels.put(channelName, c);

        return c;
    }

    public void unsubscribe(String channelName) {
        if (channels.containsKey(channelName)) {
            if (mWebSocket != null && mWebSocket.isConnected()) {
                try {
                    sendUnsubscribeMessage(channels.get(channelName));
                } catch (Exception e) {
                    if (Log.isLoggable(TAG, DEBUG))
                        Log.d(TAG, "Exception sending unsubscribe message", e);
                }
            }

            channels.remove(channelName);
        }
    }

    private void subscribeToAllChannels() {
        try {
            for (String channelName : channels.keySet()) {
                sendSubscribeMessage(channels.get(channelName));
            }
        } catch (Exception e) {
            if (Log.isLoggable(TAG, DEBUG))
                Log.d(TAG, "Exception sending subscribe message", e);
        }
    }

    /**
     * Authenticate socket id and channel
     * 
     * @param channelName
     * @return auth value
     * @throws IOException
     */
    protected String authenticate(String channelName) throws IOException {
        return null;
    }

    private void sendSubscribeMessage(Channel c) throws IOException, JSONException {
        JSONObject data = new JSONObject();
        if (c.name.startsWith("private-")) {
            String auth = authenticate(c.name);
            if (auth != null)
                data.put("auth", auth);
        }

        send("pusher:subscribe", data, c.name);
    }

    private void sendUnsubscribeMessage(Channel c) {
        JSONObject data = new JSONObject();

        send("pusher:unsubscribe", data, c.name);
    }

    public void send(String event_name, JSONObject data, String channel) {
        JSONObject message = new JSONObject();

        try {
            data.put("channel", channel);
            message.put("event", event_name);
            message.put("data", data);

            if (Log.isLoggable(TAG, DEBUG))
                Log.d(TAG, "Message: " + message.toString());
            mWebSocket.send(message.toString());
        } catch (WebSocketException e) {
            if (Log.isLoggable(TAG, DEBUG))
                Log.d(TAG, "Exception sending message", e);
        } catch (JSONException e) {
            if (Log.isLoggable(TAG, DEBUG))
                Log.d(TAG, "JSON exception", e);
        }
    }

    public void connect() {
        String prefix = mEncrypted ? HTTPS_PREFIX : HTTP_PREFIX;
        int port = mEncrypted ? WSS_PORT : WS_PORT;

        String path = "/app/" + mApplicationkey + "?client=js&version=" + VERSION;

        try {
            URI url = new URI(prefix + HOST + ":" + port + path);
            if (Log.isLoggable(TAG, DEBUG))
                Log.d(TAG, "Connecting to: " + url.toString());
            mWebSocket = new WebSocketConnection(url);
            mWebSocket.setTrustAllCerts(trustAllCerts);
            mWebSocket.setEventHandler(new WebSocketEventHandler() {
                public void onOpen() {
                    if (Log.isLoggable(TAG, DEBUG))
                        Log.d(TAG, "WebSocket Open");
                    subscribeToAllChannels();
                }

                public void onMessage(WebSocketMessage message) {
                    try {
                        if (Log.isLoggable(TAG, DEBUG))
                            Log.d(TAG, "Message: " + message.getText());

                        JSONObject jsonMessage = new JSONObject(message.getText());

                        String event = jsonMessage.optString("event", null);

                        if (event.equals("pusher:connection_established")) {
                            JSONObject data = new JSONObject(jsonMessage.getString("data"));

                            mSocketId = data.getString("socket_id");

                            if (Log.isLoggable(TAG, DEBUG))
                                Log.d(TAG, "Connection Established with Socket Id: " + mSocketId);
                        } else {
                            Bundle b = new Bundle();

                            b.putString("event", event);
                            b.putString("data", jsonMessage.getString("data"));

                            // backwards compatibility
                            b.putString("type", "pusher");
                            b.putString("message", message.getText());

                            if (jsonMessage.has("channel")) {
                                b.putString("channel", jsonMessage.getString("channel"));
                            }

                            Message msg = new Message();
                            msg.setData(b);

                            mHandler.sendMessage(msg);
                        }
                    } catch (JSONException e) {
                        if (Log.isLoggable(TAG, DEBUG))
                            Log.d(TAG, "JSON exception", e);
                    }
                }

                public void onClose() {
                    if (Log.isLoggable(TAG, DEBUG))
                        Log.d(TAG, "WebSocket Closed");
                }
            });

            mWatchdog = new Thread(new Runnable() {
                public void run() {
                    boolean interrupted = false;
                    while (!interrupted) {
                        try {
                            Thread.sleep(WATCHDOG_SLEEP_TIME_MS);
                            if (!mWebSocket.isConnected())
                                mWebSocket.connect();
                        } catch (InterruptedException e) {
                            interrupted = true;
                        } catch (Exception e) {
                            if (Log.isLoggable(TAG, DEBUG))
                                Log.d(TAG, "Exception connecting", e);
                        }
                    }
                }
            });

            mWatchdog.start();
        } catch (WebSocketException e) {
            if (Log.isLoggable(TAG, DEBUG))
                Log.d(TAG, "Web socket exception", e);
        } catch (URISyntaxException e) {
            if (Log.isLoggable(TAG, DEBUG))
                Log.d(TAG, "URI syntax exception", e);
        }
    }

    public boolean isConnected() {
        return (mWebSocket != null && mWebSocket.isConnected());
    }

    @Deprecated
    public void connect(String application_key, boolean encrypted) {
        mApplicationkey = application_key;
        mEncrypted = encrypted;
        connect();
    }

    @Deprecated
    public void connect(String application_key) {
        connect(application_key, true);
    }

    public class Channel {
        public final String name;

        public final HashMap<String, List<PusherCallback>> callbacks = new HashMap<String, List<PusherCallback>>();
        public final List<PusherCallback> globalCallbacks = new ArrayList<PusherCallback>();

        public Channel(String _name) {
            name = _name;
        }

        public Channel bind(String event, PusherCallback callback) {
            if (!callbacks.containsKey(event)) {
                callbacks.put(event, new ArrayList<PusherCallback>());
            }

            callbacks.get(event).add(callback);

            return this;
        }

        public Channel bindAll(PusherCallback callback) {
            globalCallbacks.add(callback);

            return this;
        }

        /**
         * TODO unbind should unbind callbacks from events or from the global
         * callback list instead of whole events, in order to mirror js lib
         **/
        public Channel unbind(String event) {
            if (callbacks.containsKey(event)) {
                callbacks.remove(event);
            }

            return this;
        }

        public void dispatch(String eventName, JSONObject eventData) {
            for (PusherCallback callback : globalCallbacks) {
                callback.onEvent(eventName, eventData);
            }

            if (callbacks.containsKey(eventName)) {
                for (PusherCallback callback : callbacks.get(eventName)) {
                    callback.onEvent(eventData);
                }
            }
        }
    }

    private class PusherHandler extends Handler {
        Pusher pusher;

        public PusherHandler(Pusher pusher) {
            this.pusher = pusher;
        }

        public void handleMessage(Message msg) {
            if (Log.isLoggable(TAG, DEBUG))
                Log.d(TAG, "Message handled: " + msg.getData().toString());

            try {
                String eventName = msg.getData().getString("event");

                JSONObject eventData = new JSONObject(msg.getData().getString("data"));

                pusher.globalChannel.dispatch(eventName, eventData);

                if (msg.getData().containsKey("channel")) {
                    String channelName = msg.getData().getString("channel");

                    if (pusher.channels.containsKey(channelName)) {
                        Channel channel = pusher.channels.get(channelName);

                        channel.dispatch(eventName, eventData);
                    }
                }
            } catch (JSONException e) {
                if (Log.isLoggable(TAG, DEBUG))
                    Log.d(TAG, "JSON exception", e);
            }
        }
    }
}