sk.gymdb.thinis.gcm.web.SendAllMessagesServlet.java Source code

Java tutorial

Introduction

Here is the source code for sk.gymdb.thinis.gcm.web.SendAllMessagesServlet.java

Source

/*
 * Copyright 2012 Google Inc.
 *
 * 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 sk.gymdb.thinis.gcm.web;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import sk.gymdb.thinis.gcm.server.*;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.logging.Level;

/**
 * THIS WILL GO AWAY LATER WHEN WE IMPLEMENT OUR OWN SENDING MECHANISM
 * Servlet that adds a new message to all registered devices.
 * <p/>
 * This servlet is used just by the browser (i.e., not device).
 */
@SuppressWarnings("serial")
public class SendAllMessagesServlet extends BaseServlet {

    private static final int MULTICAST_SIZE = 1000;

    private Sender sender;

    private static final Executor threadPool = Executors.newFixedThreadPool(5);

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        sender = newSender(config);
    }

    /**
     * Creates the {@link Sender} based on the servlet settings.
     */
    protected Sender newSender(ServletConfig config) {
        String key = (String) config.getServletContext().getAttribute(ApiKeyInitializer.ATTRIBUTE_ACCESS_KEY);
        return new Sender(key);
    }

    /**
     * Processes the request to add a new message.
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        List<Registration> devices = Datastore.getDevices();
        String status;
        if (devices.isEmpty()) {
            status = "Message ignored as there is no device registered!";
        } else {
            // NOTE: check below is for demonstration purposes; a real application
            // could always send a multicast, even for just one recipient
            if (devices.size() == 1) {
                // send a single message using plain post
                String registrationId = devices.get(0).getId();
                Message.Builder builder = new Message.Builder();
                builder.addData("SPRAVA", "TOTO SA MUSI ZOBRAZIT");
                Message message = builder.build();
                Result result = sender.send(message, registrationId, 5);
                status = "Sent message to one device: " + result;
            } else {
                // send a multicast message using JSON
                // must split in chunks of 1000 devices (GCM limit)
                int total = devices.size();
                List<Registration> partialDevices = new ArrayList<Registration>(total);
                int counter = 0;
                int tasks = 0;
                for (Registration device : devices) {
                    counter++;
                    partialDevices.add(device);
                    int partialSize = partialDevices.size();
                    if (partialSize == MULTICAST_SIZE || counter == total) {
                        asyncSend(partialDevices);
                        partialDevices.clear();
                        tasks++;
                    }
                }
                status = "Asynchronously sending " + tasks + " multicast messages to " + total + " devices";
            }
        }
        req.setAttribute(HomeServlet.ATTRIBUTE_STATUS, status.toString());
        getServletContext().getRequestDispatcher("/home").forward(req, resp);
    }

    private void asyncSend(List<Registration> partialDevices) {
        // make a copy
        final List<Registration> devices = new ArrayList<Registration>(partialDevices);
        threadPool.execute(new Runnable() {

            public void run() {
                Message message = new Message.Builder().build();
                MulticastResult multicastResult;
                try {
                    multicastResult = sender.send(message,
                            (List<String>) CollectionUtils.collect(devices, new Transformer() {
                                @Override
                                public Object transform(Object o) {
                                    return ((Registration) o).getId();
                                }
                            }), 5);
                } catch (IOException e) {
                    logger.log(Level.SEVERE, "Error posting messages", e);
                    return;
                }
                List<Result> results = multicastResult.getResults();
                // analyze the results
                for (int i = 0; i < devices.size(); i++) {
                    //          String regId = devices.get(i);
                    Registration registration = devices.get(i);
                    Result result = results.get(i);
                    String messageId = result.getMessageId();
                    if (messageId != null) {
                        logger.fine("Succesfully sent message to device: " + registration.getId() + "; messageId = "
                                + messageId);
                        Registration canonicalRegId = new Registration(result.getCanonicalRegistrationId(),
                                registration.getClazz());
                        if (canonicalRegId != null) {
                            // same device has more than on registration id: update it
                            logger.info("canonicalRegId " + canonicalRegId);
                            Datastore.updateRegistration(registration, canonicalRegId);
                        }
                    } else {
                        String error = result.getErrorCodeName();
                        if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
                            // application has been removed from device - unregister it
                            logger.info("Unregistered device: " + registration.getId());
                            Datastore.unregister(registration);
                        } else {
                            logger.severe("Error sending message to " + registration.getId() + ": " + error);
                        }
                    }
                }
            }
        });
    }

}