Introduction
In this part of the tutorial will implement server side implementation of our 3 main components. For this purpose we’ll use Google App Engine (GAE) to implement simple JSP web application as well GAE Datastore that is delivered with application. The entire project can be downloaded from here.
The GAE web app will have two functionalities:
- to send message to the GCM which will then dispatch notification to all targeted devices
- to store device tokens, once they are received from GCM
For messaging sending will have very simple form where we can enter some message and submit for delivery:
Figure01: Web application in Google App Engine
Setup
Step01: Visit Google App Engine web site and create a new application.
Figure02: Create GAE application
Step02: Install GAE plugin within your Eclipse. Visit here for guidelines.
Step03: Once you installed the plugin, in Eclipse go to File > New > Other and choose under Google section Web application project.
Figure03: Select GAE project in Eclipse
Step04: Name your project and namespace and uncheck the Generate project sample code option.
Figure04: Create GAE project in Eclipse
Implementation
Our web application consists of two servlets (MainActivityServlet.java, StoreIdServlet.java) and two JSP pages (main.jsp, storeid.jsp) respectively.
Figure05: GAE project structure in Eclipse
The MainActivityServlet.java servlet handles HTTP requests that are coming from the main.jsp form (see Figure01) and is in charge of sending notification messages to the GCM service. The second functionality for storing device tokens is implemented within StoreIdServlet.java servlet and it also handles requests from storeid.jsp to store device tokens manually if necessary.
Following code is the implementation of the MainActivityServlet.java servlet:
package com.guestapp;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.MulticastResult;
import com.google.android.gcm.server.Sender;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
public class MainActivityServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger log = Logger.getLogger(MainActivityServlet.class.getName());
// API_KEY is sender_auth_token (server key previously generated in GCM)
private static final String API_KEY = "";
// Datastore is database where all device tokens get stored
private static DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
// Handles HTTP GET request from the main.jsp
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("/main.jsp");
}
// Handles HTTP POST request - submit message from the main.jsp
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String txtInput = req.getParameter("txtInput");
// Instantiating sender for dispatching message to GCM
Sender sender = new Sender(API_KEY);
// Creating a message for GCM
Message message = new Message
.Builder()
.addData("message", txtInput)
.build();
ArrayList<String> devices = getAllRegIds();
if(!devices.isEmpty()){
// Sending multicast message to GCM specifying all targeting devices
MulticastResult result = sender.send(message, devices, 5);
log.info("Message posted: " + txtInput);
resp.sendRedirect("/main.jsp?message="+txtInput);
}else{
log.info("No devices registered.");
resp.sendRedirect("/main.jsp?message=warning-no-devices");
}
}
// Reads all previously stored device tokens from the database
private ArrayList<String> getAllRegIds(){
ArrayList<String> regIds = new ArrayList<String>();
Query gaeQuery = new Query("GCMDeviceIds");
PreparedQuery pq = datastore.prepare(gaeQuery);
for (Entity result : pq.asIterable()){
String id = (String) result.getProperty("regid");
regIds.add(id);
}
return regIds;
}
}
The implementation of main.jsp page looks like:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.List" %>
<%@ page import="com.google.appengine.api.users.User" %>
<%@ page import="com.google.appengine.api.users.UserService" %>
<%@ page import="com.google.appengine.api.users.UserServiceFactory" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<body>
Message:
<% if (request.getParameter("message") != null) { %>
<%= request.getParameter("message")%>
<% } %>
<form action="/main" method="post">
<div><textarea name="txtInput" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Submit" /></div>
</form>
</body>
</html>
The implementation of second StoreIdServlet.java servlet is like following:
package com.guestapp;
import java.io.IOException;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
public class StoreIdServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger log = Logger.getLogger(MainActivityServlet.class.getName());
// Datastore is database where all device tokens get stored
private static DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
// Handles HTTP GET request from the storeid.jsp
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("/storeid.jsp");
}
// Handles HTTP POST request - submit message from the storeid.jsp
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String txtRegId = req.getParameter("txtRegId");
// Creates device token entity and saves it in the database
Entity regId = new Entity("GCMDeviceIds",txtRegId);
regId.setProperty("regid", txtRegId);
if(!isReqIdExist(txtRegId)){
saveToDB(regId);
log.info("RegId inserted into DB: " + txtRegId);
}
}
// Save device token in the database
private void saveToDB(Entity regId){
datastore.put(regId);
}
// Checks if the device token already exist in the database
private boolean isReqIdExist(String regId){
Key keyRegId = KeyFactory.createKey("GCMDeviceIds", regId);
Entity entity = null;
try {
entity = datastore.get(keyRegId);
} catch (EntityNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(entity!=null){
return true;
}
return false;
}
}
The corresponding JSP page, storeid.jsp looks like:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.List" %>
<%@ page import="com.google.appengine.api.users.User" %>
<%@ page import="com.google.appengine.api.users.UserService" %>
<%@ page import="com.google.appengine.api.users.UserServiceFactory" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<body>
Insert device Registration_id:
<form action="/storeid" method="post">
<div><textarea name="txtRegId" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Submit" /></div>
</form>
</body>
</html>
Deployment
Right click on the project and go to Google > App Engine Settings… Fill in the application id that goes before “.appspot.com” part.
Figure06: GAE deployment configuration
Now go right click on the project Google > Deploy to App Engine and then click deploy.
Once your deployment is successfully finished you can go back to Google App Engine web site or check your application by visiting appid.appspot.com. Also, on Google App Engine web site you can check Datastore Viewer for preview your database records.
The remaining component of notification system is Android application. Check the implementation in the next blog.