Package org.jboss.aerogear.simplepush.server.netty

Source Code of org.jboss.aerogear.simplepush.server.netty.SimplePushSockJSService

/**
* JBoss, Home of Professional Open Source
* Copyright Red Hat, Inc., and individual contributors.
*
* 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.jboss.aerogear.simplepush.server.netty;

import static org.jboss.aerogear.simplepush.protocol.impl.json.JsonUtil.fromJson;
import static org.jboss.aerogear.simplepush.protocol.impl.json.JsonUtil.toJson;

import org.jboss.aerogear.io.netty.handler.codec.sockjs.SockJsConfig;
import org.jboss.aerogear.io.netty.handler.codec.sockjs.SockJsSessionContext;
import org.jboss.aerogear.io.netty.handler.codec.sockjs.SockJsService;

import io.netty.util.concurrent.ScheduledFuture;

import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.jboss.aerogear.simplepush.protocol.Ack;
import org.jboss.aerogear.simplepush.protocol.AckMessage;
import org.jboss.aerogear.simplepush.protocol.HelloResponse;
import org.jboss.aerogear.simplepush.protocol.MessageType;
import org.jboss.aerogear.simplepush.protocol.RegisterResponse;
import org.jboss.aerogear.simplepush.protocol.UnregisterMessage;
import org.jboss.aerogear.simplepush.protocol.UnregisterResponse;
import org.jboss.aerogear.simplepush.protocol.impl.AckMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.HelloMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.NotificationMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.PingMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.RegisterMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.UnregisterMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.json.JsonUtil;
import org.jboss.aerogear.simplepush.server.SimplePushServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* SimplePush server implementation using SockJS.
*/
public class SimplePushSockJSService implements SockJsService {

    private final Logger logger = LoggerFactory.getLogger(SimplePushSockJSService.class);

    private final UserAgents userAgents = UserAgents.getInstance();
    private final SockJsConfig sockjsConfig;
    private final SimplePushServer simplePushServer;
    private String uaid;
    private SockJsSessionContext session;
    private ScheduledFuture<?> ackJobFuture;

    /**
     * Sole constructor.
     *
     * @param sockjsConfig the SockJS {@link SockJsConfig} for this service.
     * @param simplePushServer the {@link SimplePushServer} that this instance will use.
     */
    public SimplePushSockJSService(final SockJsConfig sockjsConfig, final SimplePushServer simplePushServer) {
        this.sockjsConfig = sockjsConfig;
        this.simplePushServer = simplePushServer;
    }

    @Override
    public SockJsConfig config() {
        return sockjsConfig;
    }

    @Override
    public void onOpen(final SockJsSessionContext session) {
        logger.info("SimplePushSockJSServer onOpen");
        this.session = session;
    }

    @Override
    @SuppressWarnings("incomplete-switch")
    public void onMessage(final String message) throws Exception {
        final MessageType messageType = JsonUtil.parseFrame(message);
        logger.info("messageType: " + messageType.getMessageType());
        switch (messageType.getMessageType()) {
        case HELLO:
            if (!checkHandshakeCompleted(uaid)) {
                final HelloResponse response = simplePushServer.handleHandshake(fromJson(message, HelloMessageImpl.class));
                session.send(toJson(response));
                uaid = response.getUAID();
                userAgents.add(uaid, session);
                processUnacked(uaid, session, 0);
                logger.info("UserAgent [" + uaid + "] handshake done");
            }
            break;
        case REGISTER:
            if (checkHandshakeCompleted(uaid)) {
                final RegisterResponse response = simplePushServer.handleRegister(fromJson(message, RegisterMessageImpl.class), uaid);
                session.send(toJson(response));
                logger.info("UserAgent [" + uaid + "] Registered[" + response.getChannelId() + "]");
            }
            break;
        case UNREGISTER:
            if (checkHandshakeCompleted(uaid)) {
                final UnregisterMessage unregister = fromJson(message, UnregisterMessageImpl.class);
                final UnregisterResponse response = simplePushServer.handleUnregister(unregister, uaid);
                session.send(toJson(response));
                logger.info("UserAgent [" + uaid + "] Unregistered[" + response.getChannelId() + "]");
            }
            break;
        case ACK:
            if (checkHandshakeCompleted(uaid)) {
                final AckMessage ack = fromJson(message, AckMessageImpl.class);
                simplePushServer.handleAcknowledgement(ack, uaid);
                processUnacked(uaid, session, simplePushServer.config().acknowledmentInterval());
            }
            break;
        case PING:
            session.send(PingMessageImpl.JSON);
            break;
        }
        userAgents.updateAccessedTime(uaid);
    }

    private void processUnacked(final String uaid, final SockJsSessionContext session, final long delay) {
        final Set<Ack> unacked = simplePushServer.getUnacknowledged(uaid);
        if (unacked.isEmpty()) {
            if (ackJobFuture != null && !ackJobFuture.isCancelled()) {
                ackJobFuture.cancel(false);
                logger.info("Cancelled Re-Acknowledger job");
            }
        } else if (ackJobFuture == null) {
            ackJobFuture = session.getContext().executor().scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    final Set<Ack> unacked = simplePushServer.getUnacknowledged(uaid);
                    logger.info("Resending " + unacked);
                    session.send(toJson(new NotificationMessageImpl(unacked)));
                }
            },
                    delay,
                    simplePushServer.config().acknowledmentInterval(),
                    TimeUnit.MILLISECONDS);
        }
    }

    private boolean checkHandshakeCompleted(final String uaid) {
        if (uaid == null) {
            logger.debug("Hello frame has not been sent");
            return false;
        }
        if (!userAgents.contains(uaid)) {
            this.uaid = uaid;
            return false;
        }
        return true;
    }

    @Override
    public void onClose() {
        logger.info("SimplePushSockJSServer onClose");
        if (ackJobFuture != null) {
            ackJobFuture.cancel(true);
        }
    }

}
TOP

Related Classes of org.jboss.aerogear.simplepush.server.netty.SimplePushSockJSService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.