fi.jasoft.remoteconnection.ServerRemoteConnection.java Source code

Java tutorial

Introduction

Here is the source code for fi.jasoft.remoteconnection.ServerRemoteConnection.java

Source

/*
* Copyright 2013 John Ahlroos
*
* 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 fi.jasoft.remoteconnection;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

import com.vaadin.annotations.JavaScript;
import com.vaadin.server.AbstractExtension;
import com.vaadin.ui.UI;

import fi.jasoft.remoteconnection.client.RemoteConnectionClientRPC;
import fi.jasoft.remoteconnection.client.RemoteConnectionServerRPC;
import fi.jasoft.remoteconnection.shared.ConnectedListener;
import fi.jasoft.remoteconnection.shared.ConnectionError;
import fi.jasoft.remoteconnection.shared.IncomingChannelConnectionListener;
import fi.jasoft.remoteconnection.shared.RemoteChannel;
import fi.jasoft.remoteconnection.shared.RemoteConnection;
import fi.jasoft.remoteconnection.shared.RemoteConnectionConfiguration;
import fi.jasoft.remoteconnection.shared.RemoteConnectionDataListener;
import fi.jasoft.remoteconnection.shared.RemoteConnectionErrorHandler;
import fi.jasoft.remoteconnection.shared.RemoteConnectionState;

/**
 * Server implementation for {@link RemoteConnection}
 * 
 * @author John Ahlroos
 */
@SuppressWarnings("serial")
@JavaScript("peer.min.js")
public class ServerRemoteConnection extends AbstractExtension implements RemoteConnection {

    /**
     * A channel between two remote connections
     *
     */
    public class ServerRemoteChannel implements RemoteChannel {

        private final String id;

        private boolean connected = false;

        private List<ConnectedListener> connectedListeners = new LinkedList<ConnectedListener>();

        @Override
        public void send(String message) {
            getRpcProxy(RemoteConnectionClientRPC.class).sendMessage(id, message);
        }

        @Override
        public String getId() {
            return id;
        }

        @Override
        public boolean isConnected() {
            return connected;
        }

        @Override
        public void addConnectedListener(ConnectedListener listener) {
            connectedListeners.add(listener);
        }

        private ServerRemoteChannel(String id) {
            this.id = id;
        }

        private void messageRecieved(String message) {
            for (RemoteConnectionDataListener listener : listeners) {
                listener.dataRecieved(this, message);
            }
        }

        private void setConnected(boolean connected, String channelId) {
            this.connected = connected;
            if (connected) {
                for (ConnectedListener listener : connectedListeners) {
                    listener.connected(channelId);
                }
            }
        }
    }

    /*
     * RPC for making communication from client -> server
     */
    private RemoteConnectionServerRPC rpc = new RemoteConnectionServerRPC() {

        @Override
        public void recievedMessage(String id, String message) {
            getChannelById(id).messageRecieved(message);
        }

        @Override
        public void recievedConnection(String id) {
            ServerRemoteChannel channel = new ServerRemoteChannel(id);
            channels.add(channel);
            for (IncomingChannelConnectionListener listener : incomingListeners) {
                listener.connected(channel);
            }
        }

        @Override
        public void peerConnected(String id) {
            connected = true;
            getState(false).configuration.setId(id);
            for (ConnectedListener listener : connetedListeners) {
                listener.connected(id);
            }
        }

        @Override
        public void error(String reason) {
            if (errorHandler != null) {
                errorHandler.onConnectionError(ConnectionError.get(reason), reason);
            } else {
                System.err.println("An error occurred when connecting (" + reason + ")");
            }
        }

        @Override
        public void channelConnected(String id) {
            getChannelById(id).setConnected(true, id);
        }
    };

    // Currently open channels
    private final List<ServerRemoteChannel> channels = new LinkedList<ServerRemoteChannel>();

    // Currently attached data listeners
    private final List<RemoteConnectionDataListener> listeners = new LinkedList<RemoteConnectionDataListener>();
    private final List<IncomingChannelConnectionListener> incomingListeners = new LinkedList<IncomingChannelConnectionListener>();
    private final List<ConnectedListener> connetedListeners = new LinkedList<ConnectedListener>();

    private boolean connected = false;

    private RemoteConnectionErrorHandler errorHandler;

    /**
     * Attaches a remote connection to an UI
     * 
     * @param ui
     *       The UI to attach to
     * @return
     *       Returns the connection to communicate with remote channels with
     */
    public static ServerRemoteConnection register(UI ui) {
        return new ServerRemoteConnection(ui);
    }

    /**
     * Attaches a remote connection to an UI
     * 
     * @param ui
     *       The UI to attach to
     * @param peerId
     *       The id of this remote connection
     * @return
     *      Returns the connection to communicate with remote channels with
     */
    public static RemoteConnection register(UI ui, RemoteConnectionConfiguration configuration) {
        ServerRemoteConnection peer = register(ui);
        peer.getState().configuration = configuration;
        return peer;
    }

    @Override
    public RemoteChannel openChannel(String endpointPeerId) {
        RemoteChannel channel = getChannel(endpointPeerId);
        if (channel != null) {
            return channel;
        }

        // Open the channel on the client side
        getRpcProxy(RemoteConnectionClientRPC.class).openChannel(endpointPeerId);

        // Create channel instance
        channel = new ServerRemoteChannel(endpointPeerId);
        channels.add((ServerRemoteChannel) channel);
        return channel;
    }

    @Override
    protected RemoteConnectionState getState() {
        return (RemoteConnectionState) super.getState();
    }

    @Override
    protected RemoteConnectionState getState(boolean markAsDirty) {
        return (RemoteConnectionState) super.getState(markAsDirty);
    }

    @Override
    public void addDataListener(RemoteConnectionDataListener listener) {
        listeners.add(listener);
    }

    @Override
    public void addIncomingConnectionListener(IncomingChannelConnectionListener listener) {
        incomingListeners.add(listener);
    }

    @Override
    public void broadcast(String message) {
        for (RemoteChannel channel : channels) {
            channel.send(message);
        }
    }

    @Override
    public RemoteChannel getChannel(String endpointPeerId) {
        for (ServerRemoteChannel channel : channels) {
            if (channel.getId().equals(endpointPeerId)) {
                return channel;
            }
        }
        return null;
    }

    @Override
    public void terminate() {
        getRpcProxy(RemoteConnectionClientRPC.class).terminate();
    }

    @Override
    public void connect() {
        if (getState(false).configuration.getKey().equals(RemoteConnectionConfiguration.DEVELOPMENT_PEER_JS_KEY)) {
            getLogger().warning("You are using the development key of RemoteConnection "
                    + "with a very limited amount of connections shared among all "
                    + "RemoteConnection users. You are strongly encoraged to apply "
                    + "for your own developer key at http://peerjs.com/peerserver or "
                    + "run your own server which can be downloaded from https://github.com/peers/peerjs-server. "
                    + "You can supply your own peer server details through the RemoteConnection.getConfiguration() "
                    + "option. Thank you.");
        }

        getRpcProxy(RemoteConnectionClientRPC.class).connect();
    }

    @Override
    public boolean isConnected() {
        return connected;
    }

    @Override
    public void setErrorHandler(RemoteConnectionErrorHandler handler) {
        errorHandler = handler;
    }

    @Override
    public void addConnectedListener(ConnectedListener listener) {
        connetedListeners.add(listener);
    }

    /**
     * Default construction
     * 
     * @param ui
     *       The UI the connection should be attached to
     */
    private ServerRemoteConnection(UI ui) {
        super.extend(ui);
        registerRpc(rpc);

        // Use Vaadin's script injection
        getState().configuration.setScriptInjected(false);
    }

    /**
     * Returns, or creates a new, channel by using its remote peer id
     * 
     * @param id
     *       The peer id of the channel endpoint
     * @return
     */
    private ServerRemoteChannel getChannelById(String id) {
        for (ServerRemoteChannel channel : channels) {
            if (channel.getId().equals(id)) {
                return channel;
            }
        }
        return null;
    }

    private Logger getLogger() {
        return Logger.getLogger(ServerRemoteConnection.class.getCanonicalName());
    }

    @Override
    public RemoteConnectionConfiguration getConfiguration() {
        return getState().configuration;
    }
}