mirror of
https://github.com/fergalmoran/chrometophone.git
synced 2025-12-22 09:41:51 +00:00
Refactoring (phone-to-chrome now uses same code paths as chrome-to-phone). Bumped version number.
This commit is contained in:
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 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 com.google.android.chrometophone.server;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.google.appengine.api.channel.ChannelMessage;
|
||||
import com.google.appengine.api.channel.ChannelService;
|
||||
import com.google.appengine.api.channel.ChannelServiceFactory;
|
||||
import com.google.appengine.api.users.User;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class BrowserChannelServlet extends HttpServlet {
|
||||
private static final String OK_STATUS = "OK";
|
||||
private static final String LOGIN_REQUIRED_STATUS = "LOGIN_REQUIRED";
|
||||
private static final String ERROR_STATUS = "ERROR";
|
||||
|
||||
@Override
|
||||
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
resp.setContentType("text/plain");
|
||||
|
||||
// Basic XSRF protection
|
||||
if (req.getHeader("X-Same-Domain") == null) {
|
||||
resp.setStatus(400);
|
||||
resp.getWriter().println(ERROR_STATUS);
|
||||
return;
|
||||
}
|
||||
|
||||
User user = RegisterServlet.checkUser(req, resp, false);
|
||||
if (user == null) {
|
||||
resp.setStatus(400);
|
||||
resp.getWriter().println(LOGIN_REQUIRED_STATUS);
|
||||
} else {
|
||||
String channelToken = String.valueOf(user.hashCode()); // channel per user
|
||||
String data = req.getParameter("data");
|
||||
if (data != null) { // send data
|
||||
getChannelService().sendMessage(new ChannelMessage(channelToken, data));
|
||||
resp.getWriter().print(OK_STATUS);
|
||||
} else { // setup channel
|
||||
String channelId = getChannelService().createChannel(channelToken);
|
||||
resp.getWriter().print(channelId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ChannelService getChannelService() {
|
||||
return ChannelServiceFactory.getChannelService();
|
||||
}
|
||||
}
|
||||
@@ -31,20 +31,23 @@ import com.google.appengine.api.datastore.Key;
|
||||
|
||||
/**
|
||||
* Registration info.
|
||||
*
|
||||
*
|
||||
* An account may be associated with multiple phones,
|
||||
* and a phone may be associated with multiple accounts.
|
||||
*
|
||||
*
|
||||
* registrations lists different phones registered to that account.
|
||||
*/
|
||||
@PersistenceCapable(identityType = IdentityType.APPLICATION)
|
||||
public class DeviceInfo {
|
||||
public static final String TYPE_AC2DM = "ac2dm";
|
||||
public static final String TYPE_CHROME = "chrome";
|
||||
|
||||
/**
|
||||
* User-email # device-id
|
||||
*
|
||||
*
|
||||
* Device-id can be specified by device, default is hash of abs(registration
|
||||
* id).
|
||||
*
|
||||
*
|
||||
* user@example.com#1234
|
||||
*/
|
||||
@PrimaryKey
|
||||
@@ -54,39 +57,42 @@ public class DeviceInfo {
|
||||
@Persistent
|
||||
private String deviceRegistrationID;
|
||||
|
||||
/**
|
||||
* Each device should provide a stable ID. It can be the
|
||||
/**
|
||||
* Each device should provide a stable ID. It can be the
|
||||
* hash of the first registration, the phone ID, etc.
|
||||
* Using the name seems error-prone, users may use the default
|
||||
* which may be the same in identical phones, they may change name, etc.
|
||||
* Using the name seems error-prone, users may use the default
|
||||
* which may be the same in identical phones, they may change name, etc.
|
||||
*/
|
||||
@Persistent
|
||||
private String id;
|
||||
|
||||
|
||||
/**
|
||||
* Current supported types:
|
||||
* (default) - ac2dm, regular froyo+ devices using C2DM protocol
|
||||
*
|
||||
* New types may be defined - for example for sending to chrome.
|
||||
*
|
||||
* New types may be defined - for example for sending to chrome.
|
||||
*/
|
||||
@Persistent
|
||||
private String type;
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Friendly name for the device. May be edited by the user.
|
||||
*/
|
||||
@Persistent
|
||||
private String name;
|
||||
|
||||
|
||||
/**
|
||||
* For statistics - and to provide hints to the user.
|
||||
*/
|
||||
@Persistent
|
||||
private Date registrationTimestamp;
|
||||
|
||||
|
||||
@Persistent
|
||||
private Boolean debug;
|
||||
|
||||
@Persistent
|
||||
private Boolean phoneToChromeExperimentEnabled;
|
||||
|
||||
public DeviceInfo(Key key, String deviceRegistrationID) {
|
||||
this.key = key;
|
||||
this.deviceRegistrationID = deviceRegistrationID;
|
||||
@@ -98,13 +104,22 @@ public class DeviceInfo {
|
||||
}
|
||||
|
||||
public boolean getDebug() {
|
||||
return debug != null ? debug.booleanValue() : false;
|
||||
return (debug != null ? debug.booleanValue() : false);
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = new Boolean(debug);
|
||||
}
|
||||
|
||||
public boolean getPhoneToChromeExperimentEnabled() {
|
||||
return (phoneToChromeExperimentEnabled != null ?
|
||||
phoneToChromeExperimentEnabled.booleanValue() : false);
|
||||
}
|
||||
|
||||
public void setPhoneToChromeExperimentEnabled(boolean phoneToChromeExperimentEnabled) {
|
||||
this.phoneToChromeExperimentEnabled = new Boolean(phoneToChromeExperimentEnabled);
|
||||
}
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
@@ -121,7 +136,7 @@ public class DeviceInfo {
|
||||
this.deviceRegistrationID = deviceRegistrationID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
@@ -153,10 +168,11 @@ public class DeviceInfo {
|
||||
public Date getRegistrationTimestamp() {
|
||||
return registrationTimestamp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function - will query all registrations for a user.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<DeviceInfo> getDeviceInfoForUser(PersistenceManager pm, String user) {
|
||||
Query query = pm.newQuery(DeviceInfo.class);
|
||||
query.setFilter("key >= '" +
|
||||
@@ -170,5 +186,4 @@ public class DeviceInfo {
|
||||
query.closeAll();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,12 +21,14 @@ import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.jdo.JDOObjectNotFoundException;
|
||||
import javax.jdo.PersistenceManager;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.google.android.c2dm.server.C2DMessaging;
|
||||
import com.google.appengine.api.channel.ChannelServiceFactory;
|
||||
import com.google.appengine.api.datastore.Key;
|
||||
import com.google.appengine.api.datastore.KeyFactory;
|
||||
import com.google.appengine.api.oauth.OAuthService;
|
||||
@@ -40,10 +42,12 @@ public class RegisterServlet extends HttpServlet {
|
||||
private static final Logger log =
|
||||
Logger.getLogger(RegisterServlet.class.getName());
|
||||
private static final String OK_STATUS = "OK";
|
||||
private static final String NOT_ENABLED_STATUS = "NOT_ENABLED";
|
||||
private static final String LOGIN_REQUIRED_STATUS = "LOGIN_REQUIRED";
|
||||
private static final String ERROR_STATUS = "ERROR";
|
||||
|
||||
private static int MAX_DEVICES = 3;
|
||||
|
||||
private static int MAX_DEVICES = 5;
|
||||
|
||||
/**
|
||||
* Get the user using the UserService.
|
||||
*
|
||||
@@ -73,7 +77,7 @@ public class RegisterServlet extends HttpServlet {
|
||||
// TODO: redirect to OAuth/user service login, or send the URL
|
||||
// TODO: 401 instead of 400
|
||||
resp.setStatus(400);
|
||||
resp.getWriter().println(ERROR_STATUS + " (Not authorized)");
|
||||
resp.getWriter().println(LOGIN_REQUIRED_STATUS);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
@@ -90,8 +94,8 @@ public class RegisterServlet extends HttpServlet {
|
||||
return;
|
||||
}
|
||||
|
||||
String deviceRegistrationID = req.getParameter("devregid");
|
||||
if (deviceRegistrationID == null) {
|
||||
String deviceRegistrationId = req.getParameter("devregid");
|
||||
if (deviceRegistrationId == null) {
|
||||
resp.setStatus(400);
|
||||
resp.getWriter().println(ERROR_STATUS + "(Must specify devregid)");
|
||||
return;
|
||||
@@ -101,17 +105,17 @@ public class RegisterServlet extends HttpServlet {
|
||||
if (deviceName == null) {
|
||||
deviceName = "Phone";
|
||||
}
|
||||
|
||||
|
||||
String deviceId = req.getParameter("deviceId");
|
||||
if (deviceId == null) {
|
||||
deviceId = Long.toHexString(Math.abs(deviceRegistrationID.hashCode()));
|
||||
deviceId = Long.toHexString(Math.abs(deviceRegistrationId.hashCode()));
|
||||
}
|
||||
|
||||
String deviceType = req.getParameter("deviceType");
|
||||
if (deviceType == null) {
|
||||
deviceType = "ac2dm";
|
||||
deviceType = "ac2dm";
|
||||
}
|
||||
|
||||
|
||||
User user = checkUser(req, resp, true);
|
||||
if (user != null) {
|
||||
// Context-shared PMF.
|
||||
@@ -138,19 +142,38 @@ public class RegisterServlet extends HttpServlet {
|
||||
}
|
||||
pm.deletePersistent(oldest);
|
||||
}
|
||||
|
||||
// TODO: dup ? update
|
||||
String id = Long.toHexString(Math.abs(deviceRegistrationID.hashCode()));
|
||||
|
||||
Key key = KeyFactory.createKey(DeviceInfo.class.getSimpleName(),
|
||||
// TODO: dup ? update
|
||||
String id = Long.toHexString(Math.abs(deviceRegistrationId.hashCode()));
|
||||
|
||||
Key key = KeyFactory.createKey(DeviceInfo.class.getSimpleName(),
|
||||
user.getEmail() + "#" + id);
|
||||
|
||||
DeviceInfo device = new DeviceInfo(key, deviceRegistrationID);
|
||||
device.setId(deviceId);
|
||||
device.setName(deviceName);
|
||||
|
||||
pm.makePersistent(device);
|
||||
resp.getWriter().println(OK_STATUS);
|
||||
|
||||
// Get device if it already exists, else create
|
||||
DeviceInfo device = null;
|
||||
try {
|
||||
device = pm.getObjectById(DeviceInfo.class, key);
|
||||
} catch (JDOObjectNotFoundException e) { }
|
||||
if (device == null) {
|
||||
device = new DeviceInfo(key, deviceRegistrationId);
|
||||
device.setId(deviceId);
|
||||
device.setName(deviceName);
|
||||
device.setType(deviceType);
|
||||
pm.makePersistent(device);
|
||||
}
|
||||
|
||||
if (device.getType().equals(DeviceInfo.TYPE_CHROME)) {
|
||||
if (device.getPhoneToChromeExperimentEnabled()) {
|
||||
String channelId =
|
||||
ChannelServiceFactory.getChannelService().createChannel(deviceRegistrationId);
|
||||
resp.getWriter().println(OK_STATUS + " " + channelId);
|
||||
} else {
|
||||
resp.setStatus(400);
|
||||
resp.getWriter().println(NOT_ENABLED_STATUS);
|
||||
}
|
||||
} else {
|
||||
resp.getWriter().println(OK_STATUS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
resp.setStatus(500);
|
||||
resp.getWriter().println(ERROR_STATUS + " (Error registering device)");
|
||||
|
||||
@@ -20,15 +20,14 @@ import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.jdo.JDOObjectNotFoundException;
|
||||
import javax.jdo.PersistenceManager;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.google.android.c2dm.server.C2DMessaging;
|
||||
import com.google.appengine.api.datastore.Key;
|
||||
import com.google.appengine.api.datastore.KeyFactory;
|
||||
import com.google.appengine.api.channel.ChannelMessage;
|
||||
import com.google.appengine.api.channel.ChannelServiceFactory;
|
||||
import com.google.appengine.api.users.User;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@@ -41,23 +40,11 @@ public class SendServlet extends HttpServlet {
|
||||
private static final String ERROR_STATUS = "ERROR";
|
||||
|
||||
// GET not supported
|
||||
|
||||
|
||||
@Override
|
||||
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
resp.setContentType("text/plain");
|
||||
|
||||
// Check API version
|
||||
String apiVersionString = req.getParameter("ver");
|
||||
if (apiVersionString == null) apiVersionString = "1";
|
||||
int apiVersion = Integer.parseInt(apiVersionString);
|
||||
if (apiVersion < 3) {
|
||||
resp.setStatus(400);
|
||||
resp.getWriter().println(ERROR_STATUS +
|
||||
" (Please remove old Chrome extension and install latest)");
|
||||
log.warning("Old extension version not supported: " + apiVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic XSRF protection (TODO: remove X-Extension in a future release for consistency)
|
||||
if (req.getHeader("X-Same-Domain") == null && req.getHeader("X-Extension") == null) {
|
||||
resp.setStatus(400);
|
||||
@@ -69,45 +56,45 @@ public class SendServlet extends HttpServlet {
|
||||
String sel = req.getParameter("sel");
|
||||
if (sel == null) sel = ""; // optional
|
||||
|
||||
String url = req.getParameter("url");
|
||||
String title = req.getParameter("title");
|
||||
if (title == null) title = ""; // optional
|
||||
|
||||
String url = req.getParameter("url");
|
||||
if (url == null) {
|
||||
resp.setStatus(400);
|
||||
resp.getWriter().println(ERROR_STATUS + " (Must specify url and title parameters)");
|
||||
resp.getWriter().println(ERROR_STATUS + " (Must specify url parameter)");
|
||||
return;
|
||||
}
|
||||
if (title == null) {
|
||||
title = "";
|
||||
}
|
||||
|
||||
|
||||
String deviceId = req.getParameter("deviceId");
|
||||
String deviceName = req.getParameter("deviceName");
|
||||
String deviceType = req.getParameter("deviceType");
|
||||
if (deviceType == null) deviceType = DeviceInfo.TYPE_AC2DM;
|
||||
|
||||
User user = RegisterServlet.checkUser(req, resp, false);
|
||||
if (user != null) {
|
||||
doSendToPhone(url, title, sel, user.getEmail(), deviceId, deviceName,
|
||||
resp);
|
||||
doSendToDevice(url, title, sel, user.getEmail(),
|
||||
deviceId, deviceName, deviceType, resp);
|
||||
} else {
|
||||
resp.getWriter().println(LOGIN_REQUIRED_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doSendToPhone(String url, String title, String sel,
|
||||
String userAccount, String deviceId,
|
||||
String deviceName, HttpServletResponse resp) throws IOException {
|
||||
private boolean doSendToDevice(String url, String title, String sel, String userAccount,
|
||||
String deviceId, String deviceName, String deviceType, HttpServletResponse resp) throws IOException {
|
||||
|
||||
// ok = we sent to at least one phone.
|
||||
boolean ok = false;
|
||||
|
||||
|
||||
// Send push message to phone
|
||||
C2DMessaging push = C2DMessaging.get(getServletContext());
|
||||
boolean res = false;
|
||||
|
||||
|
||||
String collapseKey = "" + url.hashCode();
|
||||
|
||||
|
||||
PersistenceManager pm =
|
||||
C2DMessaging.getPMF(getServletContext()).getPersistenceManager();
|
||||
List<DeviceInfo> registrations = null;
|
||||
List<DeviceInfo> registrations = null;
|
||||
try {
|
||||
registrations = DeviceInfo.getDeviceInfoForUser(C2DMessaging.getPMF(getServletContext())
|
||||
.getPersistenceManager(), userAccount);
|
||||
@@ -115,24 +102,30 @@ public class SendServlet extends HttpServlet {
|
||||
pm.close();
|
||||
}
|
||||
|
||||
|
||||
if (registrations.size() == 0) {
|
||||
log.warning("Device not registered");
|
||||
resp.getWriter().println(DEVICE_NOT_REGISTERED_STATUS);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (DeviceInfo deviceInfo: registrations) {
|
||||
for (DeviceInfo deviceInfo : registrations) {
|
||||
if (deviceId != null && !deviceId.equals(deviceInfo.getId())) {
|
||||
continue; // user-specified device
|
||||
continue; // user-specified device id
|
||||
}
|
||||
if (deviceName != null && !deviceName.equals(deviceInfo.getName())) {
|
||||
continue; // user-specified device
|
||||
continue; // user-specified device name
|
||||
}
|
||||
if (deviceType != null && !deviceType.equals(deviceInfo.getType())) {
|
||||
continue; // user-specified device type
|
||||
}
|
||||
|
||||
// if name or value are null - they'll be skipped
|
||||
try {
|
||||
res = doSend(url, title, sel, push, collapseKey, deviceInfo);
|
||||
if (deviceInfo.getType().equals(DeviceInfo.TYPE_CHROME)) {
|
||||
res = doSendViaBrowserChannel(url, deviceInfo);
|
||||
} else {
|
||||
res = doSendViaC2dm(url, title, sel, push, collapseKey, deviceInfo);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
log.info("Link sent to phone! collapse_key:" + collapseKey);
|
||||
@@ -151,46 +144,52 @@ public class SendServlet extends HttpServlet {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ok) {
|
||||
resp.getWriter().println(OK_STATUS);
|
||||
return true;
|
||||
return true;
|
||||
} else {
|
||||
resp.setStatus(500);
|
||||
resp.getWriter().println(ERROR_STATUS + " (Unable to send link)");
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean doSend(String url, String title, String sel, C2DMessaging push,
|
||||
boolean doSendViaC2dm(String url, String title, String sel, C2DMessaging push,
|
||||
String collapseKey, DeviceInfo deviceInfo) throws IOException {
|
||||
|
||||
|
||||
// Trim title, sel if needed.
|
||||
if (url.length() + title.length() + sel.length() > 1000) {
|
||||
// Shorten the title - C2DM has a 1024 limit, some padding for keys
|
||||
if (title.length() > 16) {
|
||||
title = title.substring(0, 16);
|
||||
title = title.substring(0, 16);
|
||||
}
|
||||
// still not enough ?
|
||||
if (title.length() + url.length() + sel.length() > 1000) {
|
||||
// how much space we have for sel ?
|
||||
// how much space we have for sel ?
|
||||
int space = 1000 - url.length() - title.length();
|
||||
if (space > 0 && sel.length() > space) {
|
||||
sel = sel.substring(0, space);
|
||||
} // else: we'll get an error sending
|
||||
}
|
||||
// TODO: when we have history, save the url/title/sel in the history
|
||||
// TODO: when we have history, save the url/title/sel in the history
|
||||
// and send a pointer, have device fetch it.
|
||||
}
|
||||
|
||||
|
||||
boolean res;
|
||||
res = push.sendNoRetry(deviceInfo.getDeviceRegistrationID(),
|
||||
collapseKey,
|
||||
"url", url,
|
||||
collapseKey,
|
||||
"url", url,
|
||||
"title", title,
|
||||
"sel", sel,
|
||||
"debug", deviceInfo.getDebug() ? "1" : null);
|
||||
return res;
|
||||
}
|
||||
|
||||
boolean doSendViaBrowserChannel(String url, DeviceInfo deviceInfo) {
|
||||
String channelToken = deviceInfo.getDeviceRegistrationID();
|
||||
ChannelServiceFactory.getChannelService().sendMessage(
|
||||
new ChannelMessage(channelToken, url));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.google.android.c2dm.server.C2DMessaging;
|
||||
import com.google.appengine.api.datastore.Key;
|
||||
import com.google.appengine.api.datastore.KeyFactory;
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.appengine.api.users.UserService;
|
||||
import com.google.appengine.api.users.UserServiceFactory;
|
||||
@@ -57,7 +55,7 @@ public class UnregisterServlet extends HttpServlet {
|
||||
resp.getWriter().println(ERROR_STATUS + " (Must specify devregid)");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Authorize & store device info
|
||||
UserService userService = UserServiceFactory.getUserService();
|
||||
User user = userService.getCurrentUser();
|
||||
@@ -74,7 +72,7 @@ public class UnregisterServlet extends HttpServlet {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resp.getWriter().println(OK_STATUS);
|
||||
} catch (JDOObjectNotFoundException e) {
|
||||
resp.setStatus(400);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
-->
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
<application>chrometophone</application>
|
||||
<version>5</version>
|
||||
<version>6</version>
|
||||
<system-properties>
|
||||
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
|
||||
</system-properties>
|
||||
|
||||
@@ -42,12 +42,6 @@
|
||||
</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>BrowserChannelServlet</servlet-name>
|
||||
<servlet-class>com.google.android.chrometophone.server.BrowserChannelServlet
|
||||
</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>dataMessagingServlet</servlet-name>
|
||||
<servlet-class>
|
||||
@@ -80,11 +74,6 @@
|
||||
<url-pattern>/signout</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>BrowserChannelServlet</servlet-name>
|
||||
<url-pattern>/browserchannel</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>dataMessagingServlet</servlet-name>
|
||||
<url-pattern>/tasks/c2dm</url-pattern>
|
||||
|
||||
Reference in New Issue
Block a user