Package org.jboss.aerogear.simplepush.server

Source Code of org.jboss.aerogear.simplepush.server.DefaultSimplePushServer

/**
* 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;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.jboss.aerogear.crypto.RandomUtils;
import org.jboss.aerogear.simplepush.protocol.Ack;
import org.jboss.aerogear.simplepush.protocol.AckMessage;
import org.jboss.aerogear.simplepush.protocol.HelloMessage;
import org.jboss.aerogear.simplepush.protocol.HelloResponse;
import org.jboss.aerogear.simplepush.protocol.RegisterMessage;
import org.jboss.aerogear.simplepush.protocol.RegisterResponse;
import org.jboss.aerogear.simplepush.protocol.Status;
import org.jboss.aerogear.simplepush.protocol.UnregisterMessage;
import org.jboss.aerogear.simplepush.protocol.UnregisterResponse;
import org.jboss.aerogear.simplepush.protocol.impl.HelloResponseImpl;
import org.jboss.aerogear.simplepush.protocol.impl.RegisterResponseImpl;
import org.jboss.aerogear.simplepush.protocol.impl.StatusImpl;
import org.jboss.aerogear.simplepush.protocol.impl.UnregisterResponseImpl;
import org.jboss.aerogear.simplepush.protocol.impl.AckImpl;
import org.jboss.aerogear.simplepush.server.datastore.ChannelNotFoundException;
import org.jboss.aerogear.simplepush.server.datastore.DataStore;
import org.jboss.aerogear.simplepush.util.CryptoUtil;
import org.jboss.aerogear.simplepush.util.VersionExtractor;

/**
* Concrete implementation of {@link SimplePushServer} that uses a {@link DataStore} to
* store information about UserAgents and channels.
*/
public class DefaultSimplePushServer implements SimplePushServer {

    private final DataStore store;
    private final SimplePushServerConfig config;
    private final byte[] privateKey;

    /**
     * Sole constructor.
     *
     * @param store the {@link DataStore} that this server should use.
     * @param config the {@link SimplePushServerConfig} for this server.
     */
    public DefaultSimplePushServer(final DataStore store, final SimplePushServerConfig config, final byte[] privateKey) {
        this.store = store;
        this.config = config;
        this.privateKey = privateKey;
    }


    @Override
    public HelloResponse handleHandshake(final HelloMessage handshake) {
        final Set<String> oldChannels = store.getChannelIds(handshake.getUAID());
        for (String channelId : handshake.getChannelIds()) {
            if (!oldChannels.contains(channelId)) {
                store.saveChannel(new DefaultChannel(handshake.getUAID(),
                        channelId,
                        generateEndpointToken(handshake.getUAID(), channelId)));
            } else {
                oldChannels.remove(channelId);
            }
        }
        store.removeChannels(oldChannels);
        return new HelloResponseImpl(handshake.getUAID());
    }

    private String generateEndpointToken(final String uaid, final String channelId) {
        return CryptoUtil.endpointToken(uaid, channelId, privateKey);
    }

    @Override
    public RegisterResponse handleRegister(final RegisterMessage register, final String uaid) {
        final String channelId = register.getChannelId();
        final String endpointToken = generateEndpointToken(uaid, channelId);
        final boolean saved = store.saveChannel(new DefaultChannel(uaid, channelId, endpointToken));
        final Status status = saved ? new StatusImpl(200, "OK") : new StatusImpl(409, "Conflict: channeld [" + channelId + " is already in use");
        return new RegisterResponseImpl(channelId, status, makeEndpointUrl(endpointToken));
    }

    @Override
    public Notification handleNotification(final String endpointToken, final String body) throws ChannelNotFoundException {
        final Long version = Long.valueOf(VersionExtractor.extractVersion(body));
        final String channelId = store.updateVersion(endpointToken, version);
        if (channelId == null) {
            throw new ChannelNotFoundException("Could not find channel for endpoint [" + endpointToken + "]", null);
        }
        final Ack ack = new AckImpl(channelId, version);
        final String uaid = store.saveUnacknowledged(channelId, ack.getVersion());
        return new Notification(uaid, ack);
    }

    @Override
    public UnregisterResponse handleUnregister(final UnregisterMessage unregister, final String uaid) {
        final String channelId = unregister.getChannelId();
        try {
            removeChannel(channelId, uaid);
            return new UnregisterResponseImpl(channelId, new StatusImpl(200, "OK"));
        } catch (final Exception e) {
            return new UnregisterResponseImpl(channelId, new StatusImpl(500, "Could not remove the channel"));
        }
    }

    @Override
    public Set<Ack> handleAcknowledgement(final AckMessage ackMessage, final String uaid) {
        return store.removeAcknowledged(uaid, ackMessage.getAcks());
    }

    @Override
    public Set<Ack> getUnacknowledged(final String uaid) {
        return store.getUnacknowledged(uaid);
    }

    public String getUAID(final String channelId) throws ChannelNotFoundException {
        return getChannel(channelId).getUAID();
    }

    public Channel getChannel(final String channelId) throws ChannelNotFoundException {
        return store.getChannel(channelId);
    }

    public boolean hasChannel(final String uaid, final String channelId) {
        try {
            final Channel channel = store.getChannel(channelId);
            return channel.getUAID().equals(uaid);
        } catch (final ChannelNotFoundException e) {
            return false;
        }
    }

    public boolean removeChannel(final String channnelId, final String uaid) {
        try {
            final Channel channel = store.getChannel(channnelId);
            if (channel.getUAID().equals(uaid)) {
                store.removeChannels(new HashSet<String>(Arrays.asList(channnelId)));
                return true;
            }
        } catch (final ChannelNotFoundException ignored) {
        }
        return false;
    }

    private String makeEndpointUrl(final String endpointToken) {
        return config.endpointUrl() + "/" + endpointToken;
    }

    @Override
    public void removeAllChannels(final String uaid) {
        store.removeChannels(uaid);
    }

    @Override
    public SimplePushServerConfig config() {
        return config;
    }

    public static byte[] generateAndStorePrivateKey(final DataStore store, final SimplePushServerConfig config) {
        byte[] keySalt = store.getPrivateKeySalt();
        if (keySalt.length == 0) {
            keySalt = RandomUtils.randomBytes();
            store.savePrivateKeySalt(keySalt);
        }
        return CryptoUtil.secretKey(config.password(), keySalt);
    }

}
TOP

Related Classes of org.jboss.aerogear.simplepush.server.DefaultSimplePushServer

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.