blueprint.sdk.google.gcm.GcmSender.java Source code

Java tutorial

Introduction

Here is the source code for blueprint.sdk.google.gcm.GcmSender.java

Source

/*
 License:
    
 blueprint-sdk is licensed under the terms of Eclipse Public License(EPL) v1.0
 (http://www.eclipse.org/legal/epl-v10.html)
    
    
 Distribution:
    
 Repository - https://github.com/lempel/blueprint-sdk.git
 Blog - http://lempel.egloos.com
 */

package blueprint.sdk.google.gcm;

import blueprint.sdk.google.gcm.bind.Request;
import blueprint.sdk.google.gcm.bind.Response;
import blueprint.sdk.util.Validator;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

/**
 * Sends push message to GCM.
 *
 * @author Sangmin Lee
 * @since 2013. 12. 3.
 */
public class GcmSender {
    private static final Logger L = Logger.getLogger(GcmSender.class);

    @SuppressWarnings("CanBeFinal")
    public static String GCM_URL = "https://android.googleapis.com/gcm/send";

    /**
     * jackson ObjectMapper
     */
    private final ObjectMapper mapper = new ObjectMapper();

    private final String apiKey;

    /**
     * Constructor
     *
     * @param apiKey API key for GCM
     */
    public GcmSender(String apiKey) {
        this.apiKey = apiKey;
    }

    /**
     * Send to GCM
     *
     * @param json    JSON message to send
     * @param retries Number of retry attempts. Can be 0.
     * @return response from GCM
     * @throws MalformedURLException Wrong GCM_URL value
     * @throws IOException           I/O error with GCM_URL
     */
    public GcmResponse send(String json, int retries) throws IOException {
        GcmResponse result = send(json);

        int interval = 1;
        for (int i = 0; i <= retries && result.needRetry(); i++) {
            try {
                Thread.sleep(interval);
            } catch (InterruptedException ignored) {
            }

            result = send(json);

            // simplified exponential back-off
            interval *= 2;
        }

        return result;
    }

    private GcmResponse send(String json) throws IOException {
        HttpURLConnection http = (HttpURLConnection) new URL(GCM_URL).openConnection();
        http.setRequestMethod("POST");
        http.addRequestProperty("Authorization", "key=" + apiKey);
        http.addRequestProperty("Content-Type", "application/json");

        http.setDoOutput(true);
        OutputStream os = http.getOutputStream();
        os.write(json.getBytes());
        os.close();

        http.connect();

        return decodeResponse(http);
    }

    /**
     * decodes response from GCM
     *
     * @param http HTTP connection
     * @return response from GCM
     * @throws IOException
     */
    @SuppressWarnings("ResultOfMethodCallIgnored")
    private GcmResponse decodeResponse(HttpURLConnection http) throws IOException {
        GcmResponse result = new GcmResponse();
        result.code = getResponseCode(http);

        if (result.code == HttpURLConnection.HTTP_OK) {
            try {
                Response response = mapper.readValue((InputStream) http.getContent(), Response.class);
                result.multicastId = response.multicast_id;
                result.success = response.success;
                result.failure = response.failure;
                result.canonicalIds = response.canonical_ids;

                // decode 'results'
                for (Map<String, String> item : response.results) {
                    GcmResponseDetail detail = new GcmResponseDetail();

                    if (item.containsKey("message_id")) {
                        detail.success = true;
                        detail.message = item.get("message_id");
                    } else {
                        detail.success = false;
                        detail.message = item.get("error");
                    }

                    result.results.add(detail);
                }
            } catch (Exception e) {
                result.code = GcmResponse.ERR_JSON_BIND;

                L.warn("Can't bind json", e);
            }
        } else if (result.code == GcmResponse.ERR_NOT_JSON) {
            int contentLength = http.getContentLength();
            String contentType = http.getContentType();

            InputStream ins = (InputStream) http.getContent();
            byte[] buffer = new byte[contentLength];
            ins.read(buffer);

            L.warn("response message is not a json. content-type=" + contentType + ", content="
                    + new String(buffer));
        }

        return result;
    }

    /**
     * gets response code
     *
     * @param http HTTP connection
     * @return 200: http ok, 6xx: {@link GcmResponse}, others: http error
     * @throws IOException
     */
    @SuppressWarnings("IndexOfReplaceableByContains")
    private int getResponseCode(HttpURLConnection http) throws IOException {
        int result = http.getResponseCode();

        if (result == HttpURLConnection.HTTP_OK) {
            int contentLength = http.getContentLength();
            String contentType = http.getContentType();
            if (0 == contentLength) {
                result = GcmResponse.ERR_NO_CONTENT;
            } else if (Validator.isEmpty(contentType)) {
                result = GcmResponse.ERR_NO_CONTENT_TYPE;
            } else if (0 > contentType.indexOf("application/json")) {
                result = GcmResponse.ERR_NOT_JSON;
            } else {
                result = 200;
            }
        }

        return result;
    }

    /**
     * Send to GCM
     *
     * @param regIds  list of client's registration id
     * @param data    data to send
     * @param retries Number of retry attempts. Can be 0.
     * @return response from GCM
     * @throws MalformedURLException Wrong GCM_URL value
     * @throws IOException           I/O error with GCM_URL
     */
    public GcmResponse send(String[] regIds, Map<String, String> data, int retries) throws IOException {
        Request request = new Request();
        request.registration_ids = regIds;
        request.data = data;

        return send(mapper.writeValueAsString(request), retries);
    }

    /**
     * Send to GCM
     *
     * @param regId   client's registration id
     * @param data    data to send
     * @param retries Number of retry attempts. Can be 0.
     * @return response from GCM
     * @throws MalformedURLException Wrong GCM_URL value
     * @throws IOException           I/O error with GCM_URL
     */
    public GcmResponse send(String regId, Map<String, String> data, int retries) throws IOException {
        return send(new String[] { regId }, data, retries);
    }
}