com.baasbox.service.push.providers.GCMServer.java Source code

Java tutorial

Introduction

Here is the source code for com.baasbox.service.push.providers.GCMServer.java

Source

/*
 * Copyright (c) 2014.
 *
 * BaasBox - info-at-baasbox.com
 *
 * 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 com.baasbox.service.push.providers;

import static com.google.android.gcm.server.Constants.JSON_PAYLOAD;
import static com.google.android.gcm.server.Constants.JSON_REGISTRATION_IDS;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.json.simple.JSONValue;

import com.baasbox.service.logging.BaasBoxLogger;
import com.baasbox.service.logging.PushLogger;
import com.baasbox.exception.BaasBoxPushException;
import com.baasbox.service.push.PushNotInitializedException;
import com.baasbox.service.push.providers.Factory.ConfigurationKeys;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.android.gcm.server.InvalidRequestException;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.MulticastResult;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;
import com.google.common.collect.ImmutableMap;

public class GCMServer extends PushProviderAbstract {

    private String apikey;
    private boolean isInit = false;
    private final static int MAX_TIME_TO_LIVE = 2419200; //4 WEEKS

    GCMServer() {

    }

    public boolean send(String message, List<String> deviceid, JsonNode bodyJson)
            throws PushNotInitializedException, InvalidRequestException, UnknownHostException, IOException,
            PushTimeToLiveFormatException, PushCollapseKeyFormatException {
        PushLogger pushLogger = PushLogger.getInstance();
        pushLogger.addMessage("............ GCM Push Message: -%s- to the device(s) %s", message, deviceid);

        try {
            if (BaasBoxLogger.isDebugEnabled())
                BaasBoxLogger.debug("GCM Push message: " + message + " to the device " + deviceid);
            if (!isInit) {
                pushLogger.addMessage("............ GCMS is not initialized!");
                return true;
            }
            JsonNode customDataNodes = bodyJson.get("custom");

            Map<String, JsonNode> customData = new HashMap<String, JsonNode>();

            if (!(customDataNodes == null)) {
                customData.put("custom", customDataNodes);
            }

            JsonNode collapse_KeyNode = bodyJson.findValue("collapse_key");
            String collapse_key = null;

            if (!(collapse_KeyNode == null)) {
                if (!(collapse_KeyNode.isTextual()))
                    throw new PushCollapseKeyFormatException("Collapse_key MUST be a String");
                collapse_key = collapse_KeyNode.asText();
            } else
                collapse_key = "";

            JsonNode timeToLiveNode = bodyJson.findValue("time_to_live");
            int time_to_live = 0;

            if (!(timeToLiveNode == null)) {
                if (!(timeToLiveNode.isNumber()))
                    throw new PushTimeToLiveFormatException("Time_to_live MUST be a positive number or equal zero");
                else if (timeToLiveNode.asInt() < 0)
                    throw new PushTimeToLiveFormatException("Time_to_live MUST be a positive number or equal zero");
                else if (timeToLiveNode.asInt() > MAX_TIME_TO_LIVE) {
                    time_to_live = MAX_TIME_TO_LIVE;
                } else
                    time_to_live = timeToLiveNode.asInt();

            } else
                time_to_live = MAX_TIME_TO_LIVE; //IF NULL WE SET DEFAULT VALUE (4 WEEKS)

            if (BaasBoxLogger.isDebugEnabled())
                BaasBoxLogger.debug("collapse_key: " + collapse_key.toString());

            if (BaasBoxLogger.isDebugEnabled())
                BaasBoxLogger.debug("time_to_live: " + time_to_live);

            if (BaasBoxLogger.isDebugEnabled())
                BaasBoxLogger.debug("Custom Data: " + customData.toString());

            pushLogger.addMessage("............ messgae: %s", message);
            pushLogger.addMessage("............ collapse_key: %s", collapse_key);
            pushLogger.addMessage("............ time_to_live: %s", time_to_live);
            pushLogger.addMessage("............ custom: %s", customData);
            pushLogger.addMessage("............ device(s): %s", deviceid);

            Sender sender = new Sender(apikey);
            Message msg = new Message.Builder().addData("message", message).addData("custom", customData.toString())
                    .collapseKey(collapse_key.toString()).timeToLive(time_to_live).build();

            MulticastResult result = sender.send(msg, deviceid, 1);

            pushLogger.addMessage("............ %d message(s) sent", result.getTotal());
            pushLogger.addMessage("................. success: %s", result.getSuccess());
            pushLogger.addMessage("................. failure: %s", result.getFailure());

            for (Result r : result.getResults()) {
                pushLogger.addMessage("............ MessageId (null == error): %s", r.getMessageId());
                pushLogger.addMessage("............... Error Code Name: %s", r.getErrorCodeName());
                pushLogger.addMessage("............... Canonincal Registration Id: %s",
                        r.getCanonicalRegistrationId());
            }
            // icallbackPush.onError(ExceptionUtils.getMessage(e));

            // icallbackPush.onSuccess();
            return false;
        } catch (Exception e) {
            pushLogger.addMessage("Error sending push notification (GCM)...");
            pushLogger.addMessage(ExceptionUtils.getMessage(e));
            throw e;
        }

    }

    public static boolean validatePushPayload(JsonNode bodyJson) throws BaasBoxPushException {
        JsonNode collapse_KeyNode = bodyJson.findValue("collapse_key");

        if (!(collapse_KeyNode == null)) {
            if (!(collapse_KeyNode.isTextual()))
                throw new PushCollapseKeyFormatException("Collapse_key MUST be a String");
        }

        JsonNode timeToLiveNode = bodyJson.findValue("time_to_live");

        if (!(timeToLiveNode == null)) {
            if (!(timeToLiveNode.isNumber()))
                throw new PushTimeToLiveFormatException("Time_to_live MUST be a positive number or equal zero");
            else if (timeToLiveNode.asInt() < 0)
                throw new PushTimeToLiveFormatException("Time_to_live MUST be a positive number or equal zero");
        }
        return true;

    }

    @Override
    public void setConfiguration(ImmutableMap<Factory.ConfigurationKeys, String> configuration) {
        apikey = configuration.get(ConfigurationKeys.ANDROID_API_KEY);
        if (StringUtils.isNotEmpty(apikey)) {
            isInit = true;
        }
    }

    public static void validateApiKey(String apikey)
            throws MalformedURLException, IOException, PushInvalidApiKeyException {
        Message message = new Message.Builder().addData("message", "validateAPIKEY").build();
        Sender sender = new Sender(apikey);

        List<String> deviceid = new ArrayList<String>();
        deviceid.add("ABC");

        Map<Object, Object> jsonRequest = new HashMap<Object, Object>();
        jsonRequest.put(JSON_REGISTRATION_IDS, deviceid);
        Map<String, String> payload = message.getData();
        if (!payload.isEmpty()) {
            jsonRequest.put(JSON_PAYLOAD, payload);
        }
        String requestBody = JSONValue.toJSONString(jsonRequest);

        String url = com.google.android.gcm.server.Constants.GCM_SEND_ENDPOINT;
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();

        byte[] bytes = requestBody.getBytes();

        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setFixedLengthStreamingMode(bytes.length);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestProperty("Authorization", "key=" + apikey);
        OutputStream out = conn.getOutputStream();
        out.write(bytes);
        out.close();

        int status = conn.getResponseCode();
        if (status != 200) {
            if (status == 401) {
                throw new PushInvalidApiKeyException("Wrong api key");
            }
            if (status == 503) {
                throw new UnknownHostException();
            }
        }

    }

}