From 92317260d36b0711192db8b829effbcad1e22a59 Mon Sep 17 00:00:00 2001 From: harshanl Date: Wed, 18 Nov 2015 20:14:36 +0530 Subject: [PATCH] Added GCM support to android --- .../pom.xml | 6 +- .../mobile/impl/android/gcm/GCMResult.java | 53 +++++ .../mobile/impl/android/gcm/GCMService.java | 116 +---------- .../mgt/mobile/impl/android/gcm/GCMUtil.java | 191 ++++++++++++++++++ 4 files changed, 256 insertions(+), 110 deletions(-) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMResult.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMUtil.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml index c632be6be..5737b2153 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml +++ b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml @@ -73,16 +73,12 @@ org.wso2.carbon.registry.core.session, org.wso2.carbon.registry.api, org.wso2.carbon.device.mgt.extensions.license.mgt.registry, - com.google.android.gcm.*, - com.google.gson, - org.json.simple, - org.json.simple.parser + com.google.gson.*, !org.wso2.carbon.device.mgt.mobile.internal, !org.wso2.carbon.device.mgt.mobile.impl, org.wso2.carbon.device.mgt.mobile.*, - com.google.android.gcm.*, diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMResult.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMResult.java new file mode 100644 index 000000000..c15d6d4c4 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMResult.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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 org.wso2.carbon.device.mgt.mobile.impl.android.gcm; + +/** + * Represents model object for holding GCM response data. + */ +public class GCMResult { + + private String errorMsg; + private String msg; + private int statusCode; + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMService.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMService.java index 1ee07387c..2113dd062 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMService.java @@ -18,24 +18,11 @@ package org.wso2.carbon.device.mgt.mobile.impl.android.gcm; -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 org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.device.mgt.common.Device; -import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; -import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; -import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; -import org.wso2.carbon.device.mgt.mobile.impl.android.util.AndroidPluginConstants; -import org.wso2.carbon.device.mgt.mobile.internal.MobileDeviceManagementDataHolder; -import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; /** @@ -44,13 +31,11 @@ import java.util.List; public class GCMService { private static final Log log = LogFactory.getLog(GCMService.class); - public static final String GCM_APIKEY = "gcmAPIKey"; - public static final String NOTIFIER_TYPE = "notifierType"; - public static final String GCM_NOTIFIER_CODE = "2"; - private static HashMap tenantConfigurationCache = new HashMap<>(); + private static final String NOTIFIER_TYPE = "notifierType"; + private static final String GCM_NOTIFIER_CODE = "2"; public boolean isGCMEnabled() { - String notifierType = getConfigurationProperty(NOTIFIER_TYPE); + String notifierType = GCMUtil.getConfigurationProperty(NOTIFIER_TYPE); if (GCM_NOTIFIER_CODE.equals(notifierType)) { return true; } @@ -58,97 +43,18 @@ public class GCMService { } public void sendNotification(String messageData, Device device) { - int seconds = 60; - Sender sender = new Sender(getConfigurationProperty(GCM_APIKEY)); - Message message = - new Message.Builder().timeToLive(seconds).delayWhileIdle(false).addData("data", messageData).build(); - try { - Result result = sender.send(message, getGCMToken(device.getProperties()), 5); - if (result.getErrorCodeName() != null) { - log.error("Unable to send notification via GCM : " + result.getErrorCodeName()); - } - } catch (IOException e) { - log.error("Exception occurred while sending the GCM notification.",e); + List devices = new ArrayList<>(); + devices.add(device); + GCMResult result = GCMUtil.sendWakeUpCall(messageData, devices); + if (result.getStatusCode() != 200) { + log.error("Exception occurred while sending the GCM notification : " + result.getErrorMsg()); } } public void sendNotification(String messageData, List devices) { - int seconds = 60; - Sender sender = new Sender(getConfigurationProperty(GCM_APIKEY)); - Message message = - new Message.Builder().timeToLive(seconds).delayWhileIdle(false).addData("data", messageData).build(); - try { - MulticastResult result = sender.send(message, getGCMTokens(devices), 5); - if (result.getFailure() == 1) { - List resultList = result.getResults(); - if (resultList != null && resultList.size() > 0) { - Result error = resultList.get(0); - log.error("Unable to send notification via GCM : " + error.getErrorCodeName()); - } else { - log.error("Unable to send notification via GCM."); - } - } - } catch (IOException e) { - log.error("Exception occurred while sending the GCM notification.",e); + GCMResult result = GCMUtil.sendWakeUpCall(messageData, devices); + if (result.getStatusCode() != 200) { + log.error("Exception occurred while sending the GCM notification : " + result.getErrorMsg()); } } - - private static List getGCMTokens(List devices) { - List tokens = new ArrayList<>(); - for (Device device : devices) { - tokens.add(getGCMToken(device.getProperties())); - } - return tokens; - } - - private static String getGCMToken(List properties) { - String gcmToken = null; - for (Device.Property property : properties) { - if (AndroidPluginConstants.GCM_TOKEN.equals(property.getName())) { - gcmToken = property.getValue(); - break; - } - } - return gcmToken; - } - - private static String getConfigurationProperty(String property) { - DeviceManagementService androidDMService = MobileDeviceManagementDataHolder.getInstance(). - getAndroidDeviceManagementService(); - try { - //Get the TenantConfiguration from cache if not we'll get it from DM service - TenantConfiguration tenantConfiguration = getTenantConfigurationFromCache(); - if (tenantConfiguration == null) { - tenantConfiguration = androidDMService.getDeviceManager().getConfiguration(); - if (tenantConfiguration != null) { - addTenantConfigurationToCache(tenantConfiguration); - } - } - - if (tenantConfiguration != null) { - List configs = tenantConfiguration.getConfiguration(); - for (ConfigurationEntry entry : configs) { - if (property.equals(entry.getName())) { - return (String) entry.getValue(); - } - } - } - return ""; - } catch (DeviceManagementException e) { - log.error("Exception occurred while fetching the tenant-config.",e); - } - return null; - } - - private static void addTenantConfigurationToCache(TenantConfiguration tenantConfiguration) { - tenantConfigurationCache.put(getTenantId(), tenantConfiguration); - } - - private static TenantConfiguration getTenantConfigurationFromCache() { - return tenantConfigurationCache.get(getTenantId()); - } - - private static int getTenantId() { - return CarbonContext.getThreadLocalCarbonContext().getTenantId(); - } } \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMUtil.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMUtil.java new file mode 100644 index 000000000..ce08d896d --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMUtil.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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 org.wso2.carbon.device.mgt.mobile.impl.android.gcm; + +import com.google.gson.*; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; +import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; +import org.wso2.carbon.device.mgt.mobile.impl.android.util.AndroidPluginConstants; +import org.wso2.carbon.device.mgt.mobile.internal.MobileDeviceManagementDataHolder; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.ProtocolException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Implements utility methods used by GCMService. + */ +public class GCMUtil { + + private static final Log log = LogFactory.getLog(GCMService.class); + + private final static String GCM_ENDPOINT = "https://gcm-http.googleapis.com/gcm/send"; + private static final String GCM_API_KEY = "gcmAPIKey"; + private static final int TIME_TO_LIVE = 60; + private static final int HTTP_STATUS_CODE_OK = 200; + + private static HashMap tenantConfigurationCache = new HashMap<>(); + + public static GCMResult sendWakeUpCall(String message, List devices) { + GCMResult result = new GCMResult(); + + byte[] bytes = getGCMRequest(message, getGCMTokens(devices)).getBytes(); + HttpURLConnection conn; + try { + conn = (HttpURLConnection) (new URL(GCM_ENDPOINT)).openConnection(); + conn.setDoOutput(true); + conn.setUseCaches(false); + conn.setFixedLengthStreamingMode(bytes.length); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/json"); + conn.setRequestProperty("Authorization", "key=" + getConfigurationProperty(GCM_API_KEY)); + + OutputStream out = conn.getOutputStream(); + out.write(bytes); + out.close(); + + int status = conn.getResponseCode(); + result.setStatusCode(status); + if (status != HTTP_STATUS_CODE_OK) { + result.setErrorMsg(getString(conn.getErrorStream())); + } else { + result.setMsg(getString(conn.getInputStream())); + } + } catch (ProtocolException e) { + log.error("Exception occurred while setting the HTTP protocol.", e); + } catch (IOException ex) { + log.error("Exception occurred while sending the GCM request.", ex); + } + + return result; + } + + private static String getString(InputStream stream) throws IOException { + if (stream != null) { + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + StringBuilder content = new StringBuilder(); + + String newLine; + do { + newLine = reader.readLine(); + if (newLine != null) { + content.append(newLine).append('\n'); + } + } while (newLine != null); + + if (content.length() > 0) { + content.setLength(content.length() - 1); + } + + return content.toString(); + } + return null; + } + + private static String getGCMRequest(String message, List registrationIds) { + JsonObject gcmRequest = new JsonObject(); + gcmRequest.addProperty("delay_while_idle", false); + gcmRequest.addProperty("time_to_live", TIME_TO_LIVE); + + //Add message to GCM request + JsonObject data = new JsonObject(); + if (message != null && !message.isEmpty()) { + data.addProperty("data", message); + gcmRequest.add("data", data); + } + + //Set device reg-ids + JsonArray regIds = new JsonArray(); + for (String regId : registrationIds) { + regIds.add(new JsonPrimitive(regId)); + } + + gcmRequest.add("registration_ids", regIds); + return gcmRequest.toString(); + } + + private static List getGCMTokens(List devices) { + List tokens = new ArrayList<>(); + for (Device device : devices) { + tokens.add(getGCMToken(device.getProperties())); + } + return tokens; + } + + private static String getGCMToken(List properties) { + String gcmToken = null; + for (Device.Property property : properties) { + if (AndroidPluginConstants.GCM_TOKEN.equals(property.getName())) { + gcmToken = property.getValue(); + break; + } + } + return gcmToken; + } + + public static String getConfigurationProperty(String property) { + DeviceManagementService androidDMService = MobileDeviceManagementDataHolder.getInstance(). + getAndroidDeviceManagementService(); + try { + //Get the TenantConfiguration from cache if not we'll get it from DM service + TenantConfiguration tenantConfiguration = getTenantConfigurationFromCache(); + if (tenantConfiguration == null) { + tenantConfiguration = androidDMService.getDeviceManager().getConfiguration(); + if (tenantConfiguration != null) { + addTenantConfigurationToCache(tenantConfiguration); + } + } + + if (tenantConfiguration != null) { + List configs = tenantConfiguration.getConfiguration(); + for (ConfigurationEntry entry : configs) { + if (property.equals(entry.getName())) { + return (String) entry.getValue(); + } + } + } + return ""; + } catch (DeviceManagementException e) { + log.error("Exception occurred while fetching the tenant-config.",e); + } + return null; + } + + private static void addTenantConfigurationToCache(TenantConfiguration tenantConfiguration) { + tenantConfigurationCache.put(getTenantId(), tenantConfiguration); + } + + private static TenantConfiguration getTenantConfigurationFromCache() { + return tenantConfigurationCache.get(getTenantId()); + } + + private static int getTenantId() { + return CarbonContext.getThreadLocalCarbonContext().getTenantId(); + } +} \ No newline at end of file