From 60e97b9c9a4fc80768c781f394c8ea0a7a319896 Mon Sep 17 00:00:00 2001 From: kirillov Date: Fri, 27 Feb 2015 09:55:15 +0000 Subject: [PATCH 1/5] Adding example code for notifications --- examples/emm-notifications/.gitignore | 6 + .../google_settings.properties | 5 + examples/emm-notifications/pom.xml | 110 +++++++++++++++++ examples/emm-notifications/run-publisher.sh | 6 + examples/emm-notifications/run-subscriber.sh | 7 ++ .../emm-notifications/settings.properties | 2 + .../android/work/emmnotifications/Common.java | 61 ++++++++++ .../work/emmnotifications/PushSubscriber.java | 111 ++++++++++++++++++ .../RetryHttpInitializerWrapper.java | 91 ++++++++++++++ .../ServiceAccountConfiguration.java | 54 +++++++++ .../work/emmnotifications/Settings.java | 74 ++++++++++++ .../notpublic/FauxPublisher.java | 79 +++++++++++++ .../notpublic/PullSubscriber.java | 79 +++++++++++++ .../src/main/proto/emm_pubsub.proto | 32 +++++ .../work/emmnotifications/AppTest.java | 38 ++++++ 15 files changed, 755 insertions(+) create mode 100644 examples/emm-notifications/.gitignore create mode 100644 examples/emm-notifications/google_settings.properties create mode 100644 examples/emm-notifications/pom.xml create mode 100755 examples/emm-notifications/run-publisher.sh create mode 100755 examples/emm-notifications/run-subscriber.sh create mode 100644 examples/emm-notifications/settings.properties create mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Common.java create mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/PushSubscriber.java create mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/RetryHttpInitializerWrapper.java create mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/ServiceAccountConfiguration.java create mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Settings.java create mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/FauxPublisher.java create mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/PullSubscriber.java create mode 100644 examples/emm-notifications/src/main/proto/emm_pubsub.proto create mode 100644 examples/emm-notifications/src/test/java/com/google/android/work/emmnotifications/AppTest.java diff --git a/examples/emm-notifications/.gitignore b/examples/emm-notifications/.gitignore new file mode 100644 index 0000000..0743fe9 --- /dev/null +++ b/examples/emm-notifications/.gitignore @@ -0,0 +1,6 @@ +.idea +target +.DS_Store +../.DS_Store +emm-notifications.iml +.idea diff --git a/examples/emm-notifications/google_settings.properties b/examples/emm-notifications/google_settings.properties new file mode 100644 index 0000000..5bcaed4 --- /dev/null +++ b/examples/emm-notifications/google_settings.properties @@ -0,0 +1,5 @@ +# NOT PUBLIC +# Values for our internal developer console project (enterprise-cloud-pub-sub) + +ServiceAccountEmail=368628613713-t4hf388f34tdn5lhpdcu1qqfgio01626@developer.gserviceaccount.com +ServiceAccountP12KeyFile=secret.p12 \ No newline at end of file diff --git a/examples/emm-notifications/pom.xml b/examples/emm-notifications/pom.xml new file mode 100644 index 0000000..a32affa --- /dev/null +++ b/examples/emm-notifications/pom.xml @@ -0,0 +1,110 @@ + + 4.0.0 + com.google.android.work.emmnotifications + emm-notifications + jar + 1.0-SNAPSHOT + emm-notifications + http://maven.apache.org + + + + protoc-plugin + http://sergei-ivanov.github.com/maven-protoc-plugin/repo/releases/ + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + 1.5 + + + + com.google.protobuf.tools + maven-protoc-plugin + 0.3.2 + + /usr/bin/protoc + + + + + compile + testCompile + + + + + + maven-assembly-plugin + + + + fully.qualified.MainClass + + + + jar-with-dependencies + + + + + + + + + junit + junit + 3.8.1 + test + + + com.google.protobuf + protobuf-java + 2.6.1 + + + junit + junit + 3.8.1 + test + + + com.google.apis + google-api-services-pubsub + LATEST + + + com.google.api-client + google-api-client + 1.18.0-rc + + + com.google.oauth-client + google-oauth-client-java6 + 1.15.0-rc + + + com.google.http-client + google-http-client-jackson2 + 1.19.0 + + + com.google.guava + guava + 18.0 + + + commons-cli + commons-cli + 1.2 + + + diff --git a/examples/emm-notifications/run-publisher.sh b/examples/emm-notifications/run-publisher.sh new file mode 100755 index 0000000..8e45216 --- /dev/null +++ b/examples/emm-notifications/run-publisher.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +mvn clean compile assembly:single && \ +java -cp target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar \ + com.google.android.work.emmnotifications.notpublic.FauxPublisher \ + --topic_name=projects/enterprise-cloud-pub-sub/topics/hello-world-topic \ No newline at end of file diff --git a/examples/emm-notifications/run-subscriber.sh b/examples/emm-notifications/run-subscriber.sh new file mode 100755 index 0000000..d0a46fc --- /dev/null +++ b/examples/emm-notifications/run-subscriber.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mvn clean compile assembly:single && \ +java -cp target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar \ + com.google.android.work.emmnotifications.PushSubscriber \ + --subscription_name=projects/enterprise-cloud-pub-sub/subscriptions/hello-world-push-subscription \ + --topic_name=projects/enterprise-cloud-pub-sub/topics/hello-world-topic \ No newline at end of file diff --git a/examples/emm-notifications/settings.properties b/examples/emm-notifications/settings.properties new file mode 100644 index 0000000..2bc061b --- /dev/null +++ b/examples/emm-notifications/settings.properties @@ -0,0 +1,2 @@ +ServiceAccountEmail=changeme@gserviceaccount.com +ServiceAccountP12KeyFile=/path/to/key.p12 \ No newline at end of file diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Common.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Common.java new file mode 100644 index 0000000..fed41d9 --- /dev/null +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Common.java @@ -0,0 +1,61 @@ +package com.google.android.work.emmnotifications; + +import com.google.api.services.pubsub.Pubsub; +import org.apache.commons.cli.*; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.logging.Logger; + +public class Common { + private static final Logger LOG = Logger.getLogger(Common.class.getName()); + + public static final String TOPIC_NAME = "topic_name"; + public static final String SUBSCRIPTION_NAME = "subscription_name"; + public static final String PROJECT_NAME = "project_name"; + + private static final String DEFAULT_PROJECT_NAME = "enterprise-cloud-pub-sub"; + + public static CommandLine getCommandLine(String[] args) throws ParseException { + Options options = new Options(); + + options.addOption("t", TOPIC_NAME, true, "Topic name"); + options.addOption("s", SUBSCRIPTION_NAME, true, "Subscription name"); + options.addOption("p", PROJECT_NAME, true, "Developer Console project name, e.g. cloud-pub-sub"); + + CommandLineParser parser = new GnuParser(); + CommandLine commandLine = parser.parse(options, args); + + // If project name is specified we will use default topic and subscription name + // If non-default topic and/or subscription name are specified, then project name makes no sense. + if (commandLine.hasOption(PROJECT_NAME) && + (commandLine.hasOption(TOPIC_NAME) || commandLine.hasOption(SUBSCRIPTION_NAME))) { + LOG.warning("Either --" + PROJECT_NAME + + " or combination of --" + TOPIC_NAME + + " and --" + SUBSCRIPTION_NAME + + " can be set"); + + System.exit(2); + } + + return commandLine; + } + + public static Pubsub makePubsubClient() throws IOException, GeneralSecurityException { + return ServiceAccountConfiguration.createPubsubClient( + Settings.getSettings().getServiceAccountEmail(), + Settings.getSettings().getServiceAccountP12KeyPath()); + } + + public static String getDefaultProjectName() { + return DEFAULT_PROJECT_NAME; + } + + public static String getDefaultTopicName() { + return "projects/" + getDefaultProjectName() + "/topics/hello-world-topic"; + } + + public static String getDefaultSubscriptionName() { + return "projects/" + getDefaultProjectName() + "/subscriptions/hello-world-sub"; + } +} diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/PushSubscriber.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/PushSubscriber.java new file mode 100644 index 0000000..6be719f --- /dev/null +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/PushSubscriber.java @@ -0,0 +1,111 @@ +package com.google.android.work.emmnotifications; + +import com.google.android.work.pubsub.EmmPubsub; +import com.google.api.client.http.HttpResponseException; +import com.google.api.client.json.JsonParser; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.pubsub.Pubsub; +import com.google.api.services.pubsub.model.PubsubMessage; +import com.google.api.services.pubsub.model.PushConfig; +import com.google.api.services.pubsub.model.Subscription; +import com.google.common.io.CharStreams; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import org.apache.commons.cli.CommandLine; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetSocketAddress; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * THIS WILL BE EXTERNAL CODE + */ +public class PushSubscriber { + private static final String PUSH_ENDPOINT = "https://e.r-k.co"; + private static final int PORT = 8093; + + private static final Logger LOG = Logger.getLogger(PushSubscriber.class.getName()); + public static final String MESSAGE_FIELD = "message"; + + public static void main(String[] args) throws Exception { + CommandLine commandLine = Common.getCommandLine(args); + Pubsub client = Common.makePubsubClient(); + + // First we check if subscription actually exists for this subscription name. + Subscription subscription = null; + + String topicName = commandLine.getOptionValue(Common.TOPIC_NAME, Common.getDefaultTopicName()); + String subName = commandLine.getOptionValue(Common.SUBSCRIPTION_NAME, Common.getDefaultSubscriptionName()); + + LOG.info("Will be using topic name: " + topicName + ", subscription name: " + subName); + + try { + LOG.info("Trying to get subscription named " + subName); + subscription = client + .projects() + .subscriptions() + .get(subName) + .execute(); + + LOG.info("Will be re-using existing subscription: " + subscription.toPrettyString()); + } catch (HttpResponseException e) { + + // subscription not found + if (e.getStatusCode() == 404) { + LOG.info("Subscription doesn't exist, will try to create " + subName); + + // Creating subscription + subscription = client + .projects() + .subscriptions() + .create(subName, new Subscription() + .setTopic(topicName) // Name of the topic it subscribes to + .setAckDeadlineSeconds(600) + .setPushConfig(new PushConfig() + .setPushEndpoint(PUSH_ENDPOINT))) // FQDN with valid SSL certificate + .execute(); + + LOG.info("Created: " + subscription.toPrettyString()); + } + } + + // Kicking off HttpServer which will listen on specified port and process all + // incoming push pub/sub notifications + HttpServer server = HttpServer.create(new InetSocketAddress(PORT), 0); + server.createContext("/", new HttpHandler() { + public void handle(HttpExchange httpExchange) throws IOException { + String rawRequest = CharStreams.toString(new InputStreamReader(httpExchange.getRequestBody())); + LOG.info("Raw request: " + rawRequest); + + try { + // Note, that documentation says this is PubsubMessage, which it isn't + JsonParser parser = JacksonFactory.getDefaultInstance().createJsonParser(rawRequest); + parser.skipToKey(MESSAGE_FIELD); + + PubsubMessage message = parser.parseAndClose(PubsubMessage.class); + LOG.info("Pubsub message received: " + message.toPrettyString()); + + // Decoding Protocol Buffers message from array of bytes + EmmPubsub.MdmPushNotification mdmPushNotification = EmmPubsub.MdmPushNotification + .newBuilder() + .mergeFrom(message.decodeData()) + .build(); + + LOG.info("Message received: " + mdmPushNotification.toString()); + } catch (Throwable e) { + LOG.log(Level.WARNING, "Error occured when decoding message", e); + } + + // CloudPubSub will interpret 2XX as ACK, anything that isn't 2XX will trigger a retry + httpExchange.sendResponseHeaders(204, 0); + httpExchange.close(); + } + }); + + server.setExecutor(null); + server.start(); // Will keep running until killed + } +} diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/RetryHttpInitializerWrapper.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/RetryHttpInitializerWrapper.java new file mode 100644 index 0000000..564ccaa --- /dev/null +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/RetryHttpInitializerWrapper.java @@ -0,0 +1,91 @@ +package com.google.android.work.emmnotifications; + +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.http.*; +import com.google.api.client.util.ExponentialBackOff; +import com.google.api.client.util.Sleeper; +import com.google.common.base.Preconditions; +import com.google.common.io.CharStreams; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.logging.Logger; + +/** + * RetryHttpInitializerWrapper will automatically retry upon RPC + * failures, preserving the auto-refresh behavior of the Google + * Credentials. + */ +public class RetryHttpInitializerWrapper implements HttpRequestInitializer { + + private static final Logger LOG = + Logger.getLogger(RetryHttpInitializerWrapper.class.getName()); + + // Intercepts the request for filling in the "Authorization" + // header field, as well as recovering from certain unsuccessful + // error codes wherein the Credential must refresh its token for a + // retry. + private final Credential wrappedCredential; + + // A sleeper; you can replace it with a mock in your test. + private final Sleeper sleeper; + + public RetryHttpInitializerWrapper(Credential wrappedCredential) { + this(wrappedCredential, Sleeper.DEFAULT); + } + + // Use only for testing. + RetryHttpInitializerWrapper( + Credential wrappedCredential, Sleeper sleeper) { + this.wrappedCredential = Preconditions.checkNotNull(wrappedCredential); + this.sleeper = sleeper; + } + + public void initialize(HttpRequest request) { + final HttpUnsuccessfulResponseHandler backoffHandler = + new HttpBackOffUnsuccessfulResponseHandler( + new ExponentialBackOff()) + .setSleeper(sleeper); + request.setInterceptor(wrappedCredential); + + request.setConnectTimeout(3 * 60000); // 3 minutes connect timeout + request.setReadTimeout(3 * 60000); // 3 minutes read timeout + + request.setUnsuccessfulResponseHandler( + new HttpUnsuccessfulResponseHandler() { + public boolean handleResponse( + HttpRequest request, + HttpResponse response, + boolean supportsRetry) throws IOException { + + LOG.info("RetryHandler: " + CharStreams.toString( + new InputStreamReader(response.getContent()))); + + if (wrappedCredential.handleResponse( + request, response, supportsRetry)) { + // If credential decides it can handle it, + // the return code or message indicated + // something specific to authentication, + // and no backoff is desired. + + LOG.info("Requested: " + request.getUrl().toString()); + return true; + } else if (backoffHandler.handleResponse( + request, response, supportsRetry)) { + + // Otherwise, we defer to the judgement of + // our internal backoff handler. + LOG.info("Retrying " + request.getUrl()); + return true; + } else { + return false; + } + } + }); + request.setIOExceptionHandler( + new HttpBackOffIOExceptionHandler(new ExponentialBackOff()) + .setSleeper(sleeper)); + } + + +} \ No newline at end of file diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/ServiceAccountConfiguration.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/ServiceAccountConfiguration.java new file mode 100644 index 0000000..edda8d6 --- /dev/null +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/ServiceAccountConfiguration.java @@ -0,0 +1,54 @@ +package com.google.android.work.emmnotifications; + +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.HttpRequestInitializer; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.pubsub.Pubsub; +import com.google.api.services.pubsub.PubsubScopes; + +import java.io.File; +import java.io.IOException; +import java.security.GeneralSecurityException; + +/** + * Create a Pubsub client with the service account. + */ +public class ServiceAccountConfiguration { + + private static final JsonFactory JSON_FACTORY = + JacksonFactory.getDefaultInstance(); + + public static Pubsub createPubsubClient(String serviceAccountEmail, String privateKeyFilePath) + throws IOException, GeneralSecurityException { + HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport(); + GoogleCredential credential = new GoogleCredential.Builder() + .setTransport(transport) + .setJsonFactory(JSON_FACTORY) + .setServiceAccountScopes(PubsubScopes.all()) + + // Obtain this from the "APIs & auth" -> "Credentials" + // section in the Google Developers Console: + // https://console.developers.google.com/ + // (and put the e-mail address into your system property obviously) + .setServiceAccountId(serviceAccountEmail) + + // Download this file from "APIs & auth" -> "Credentials" + // section in the Google Developers Console: + // https://console.developers.google.com/ + .setServiceAccountPrivateKeyFromP12File(new File(privateKeyFilePath)) + .build(); + + + // Please use custom HttpRequestInitializer for automatic + // retry upon failures. We provide a simple reference + // implementation in the "Retry Handling" section. + HttpRequestInitializer initializer = + new RetryHttpInitializerWrapper(credential); + return new Pubsub.Builder(transport, JSON_FACTORY, initializer) + .setApplicationName("PubSub Example") + .build(); + } +} \ No newline at end of file diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Settings.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Settings.java new file mode 100644 index 0000000..51f9aff --- /dev/null +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Settings.java @@ -0,0 +1,74 @@ +package com.google.android.work.emmnotifications; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Properties; +import java.util.logging.Logger; + +import static com.google.api.client.util.Preconditions.checkArgument; +import static com.google.api.client.util.Preconditions.checkNotNull; + +/** + * Loads settings from settings.properties or file specified in DEVELOPER_CONSOLE_SETTINGS env variable. + */ +public class Settings { + private static final String EMAIL = "ServiceAccountEmail"; + private static final String KEY = "ServiceAccountP12KeyFile"; + + private static final String EMAIL_DEFAULT = "changeme@gserviceaccount.com"; + private static final String KEY_DEFAULT = "/path/to/key.p12"; + + private static final Logger LOG = Logger.getLogger(Settings.class.getName()); + public static final String SETTINGS_ENV_VAR_NAME = "DEVELOPER_CONSOLE_SETTINGS"; + + private static Settings settings = null; + + private String serviceAccountEmail; + private String serviceAccountP12KeyPath; + + private Settings(String serviceAccountEmail, String serviceAccountP12KeyPath) { + this.serviceAccountEmail = serviceAccountEmail; + this.serviceAccountP12KeyPath = serviceAccountP12KeyPath; + } + + /** + * @return a singleton instance of Settings + * @throws IOException + */ + public static Settings getSettings() throws IOException { + if (settings != null) { + return settings; + } + + String settingsFilePath = "settings.properties"; + + String settingsEnvVariable = null; + if ((settingsEnvVariable = System.getenv(SETTINGS_ENV_VAR_NAME)) != null) { + settingsFilePath = settingsEnvVariable; + } + + Properties properties = new Properties(); + properties.load(new InputStreamReader(new FileInputStream(new File(settingsFilePath)))); + + String email = properties.getProperty(EMAIL); + String key = properties.getProperty(KEY); + + checkNotNull(email, EMAIL + " must be set in " + settingsFilePath); + checkArgument(!email.equals(EMAIL_DEFAULT), "You must specify non-default " + EMAIL + " in " + settingsFilePath); + + checkNotNull(key, KEY + " must be set in " + settingsFilePath); + checkArgument(!key.equals(KEY_DEFAULT), "You must specify non-default " + KEY + " in " + settingsFilePath); + + return (settings = new Settings(email, key)); + }; + + public String getServiceAccountEmail() { + return serviceAccountEmail; + } + + public String getServiceAccountP12KeyPath() { + return serviceAccountP12KeyPath; + } +} diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/FauxPublisher.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/FauxPublisher.java new file mode 100644 index 0000000..1a3d906 --- /dev/null +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/FauxPublisher.java @@ -0,0 +1,79 @@ +package com.google.android.work.emmnotifications.notpublic; + +import com.google.android.work.emmnotifications.Common; +import com.google.android.work.pubsub.EmmPubsub; +import com.google.api.client.http.HttpResponseException; +import com.google.api.services.pubsub.Pubsub; +import com.google.api.services.pubsub.model.PublishRequest; +import com.google.api.services.pubsub.model.PubsubMessage; +import com.google.api.services.pubsub.model.Topic; +import com.google.common.collect.ImmutableList; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.ParseException; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.logging.Logger; + +/** + * ---- NOT PUBLIC CODE ---- + * + * This is a faux publisher which can be used to simulate messages that would be normally sent by + * Enterprise Server + */ +public class FauxPublisher { + + private static final Logger LOG = + Logger.getLogger(FauxPublisher.class.getName()); + + public static void main(String[] args) throws ParseException, IOException, GeneralSecurityException { + + CommandLine commandLine = Common.getCommandLine(args); + Pubsub pubsubClient = Common.makePubsubClient(); + String topicName = commandLine.getOptionValue(Common.TOPIC_NAME, Common.getDefaultTopicName()); + + try { + Topic topic = pubsubClient + .projects() + .topics() + .get(topicName) + .execute(); + + LOG.info("Topic " + topicName + " exists: " + topic.toPrettyString()); + } catch (HttpResponseException e) { + if (e.getStatusCode() == 404) { + // Topic doesn't exist? + LOG.info("Topic " + topicName + " doesn't exists, creating it"); + pubsubClient + .projects() + .topics() + .create(topicName, new Topic()) + .execute(); + LOG.info("Topic " + topicName + " created"); + } + } + + ImmutableList.Builder listBuilder = ImmutableList.builder(); + + EmmPubsub.MdmPushNotification mdmPushNotification = EmmPubsub.MdmPushNotification.newBuilder() + .addProductApprovalEvent(EmmPubsub.ProductApprovalEvent.newBuilder() + .setApproved(false) + .setProductId("com.google.android.gms") + .setCommonEventInformation(EmmPubsub.MdmNotificationEnterpriseEventCommon.newBuilder() + .setEnterpriseId("12321321") + .setEventNotificationSentTimestamp("right now"))) + .build(); + + pubsubClient + .projects() + .topics() + .publish( + topicName, + new PublishRequest() + .setMessages(ImmutableList.of( + new PubsubMessage() + .encodeData(mdmPushNotification.toByteArray())))) + .execute(); + } + +} diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/PullSubscriber.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/PullSubscriber.java new file mode 100644 index 0000000..d8ec46b --- /dev/null +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/PullSubscriber.java @@ -0,0 +1,79 @@ +package com.google.android.work.emmnotifications.notpublic; + +import com.google.android.work.emmnotifications.Common; +import com.google.api.client.http.HttpResponseException; +import com.google.api.services.pubsub.Pubsub; +import com.google.api.services.pubsub.model.*; +import com.google.common.collect.ImmutableList; +import org.apache.commons.cli.CommandLine; + +import java.net.SocketTimeoutException; +import java.util.logging.Logger; + +/** + * ---- NOT PUBLIC CODE ---- + * + * Cloud PubSub backends currently 500's when trying to ACK the message therefore this code is NOT PUBLIC. + */ +public class PullSubscriber { + private static final Logger LOG = Logger.getLogger(PullSubscriber.class.getName()); + + public static void main(String[] args) throws Exception { + CommandLine commandLine = Common.getCommandLine(args); + Pubsub client = Common.makePubsubClient(); + String topicName = commandLine.getOptionValue(Common.TOPIC_NAME, Common.getDefaultTopicName()); + String subName = commandLine.getOptionValue(Common.SUBSCRIPTION_NAME, Common.getDefaultSubscriptionName()); + Subscription subscription = null; + + try { + LOG.info("Trying to get subscription " + subName); + + subscription = client + .projects() + .subscriptions() + .get(subName) + .execute(); + + LOG.info("Got subscription back: " + subscription.toPrettyString()); + } catch (HttpResponseException e) { + throw e; + } + + PullRequest pullRequest = new PullRequest().setReturnImmediately(false).setMaxMessages(10); + + LOG.info("Will be polling: " + pullRequest.toPrettyString()); + + while (true) { + PullResponse response = null; + try { + response = client + .projects() + .subscriptions() + .pull(subName, pullRequest).execute(); + } catch (SocketTimeoutException e) { + // Something went wrong, try again in a bit + LOG.info("Timed out waiting for data, repeating in 1 second..."); + Thread.sleep(1000); + continue; + } + + ImmutableList.Builder ackIdsBuilder = ImmutableList.builder(); + for (ReceivedMessage msg : response.getReceivedMessages()) { + PubsubMessage message = msg.getMessage(); + String ackId = message.getMessageId(); + + LOG.info("Will be ack'ing " + ackId); + ackIdsBuilder.add(ackId); + } + + AcknowledgeRequest ack = new AcknowledgeRequest().setAckIds(ackIdsBuilder.build()); + client + .projects() + .subscriptions() + .acknowledge(subName, ack) + .execute(); + + Thread.sleep(500); + } + } +} diff --git a/examples/emm-notifications/src/main/proto/emm_pubsub.proto b/examples/emm-notifications/src/main/proto/emm_pubsub.proto new file mode 100644 index 0000000..3a2d640 --- /dev/null +++ b/examples/emm-notifications/src/main/proto/emm_pubsub.proto @@ -0,0 +1,32 @@ +syntax = "proto2"; + +option java_package = "com.google.android.work.pubsub"; + +// A notification delivered to an MDM to inform them of one or more event(s) +// relating to an enterprise. +message MdmPushNotification { + // Delivers notifications about changes to a product's approval status. + repeated ProductApprovalEvent product_approval_event = 1; +} + +// Common information applicable to multiple types of event contained within +// an MdmPushNotification message that concern a specific enterprise. +message MdmNotificationEnterpriseEventCommon { + // [Required] The ID of the enterprise that the event concerns. + optional string enterprise_id = 1; + + // [Required] The time when the event notification was published. + optional string event_notification_sent_timestamp = 2; +} + +// An event generated when a product's approval status is changed. +message ProductApprovalEvent { + // [Required] Common information regarding an enterprise event. + optional MdmNotificationEnterpriseEventCommon common_event_information = 1; + + // [Required] The ID of the product. + optional string product_id = 2; + + // [Required] Whether the product was approved or unapproved. + optional bool approved = 3; +} \ No newline at end of file diff --git a/examples/emm-notifications/src/test/java/com/google/android/work/emmnotifications/AppTest.java b/examples/emm-notifications/src/test/java/com/google/android/work/emmnotifications/AppTest.java new file mode 100644 index 0000000..fcaa15f --- /dev/null +++ b/examples/emm-notifications/src/test/java/com/google/android/work/emmnotifications/AppTest.java @@ -0,0 +1,38 @@ +package com.google.android.work.emmnotifications; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} From ecb3840e3d207c49d3bb9e00c09dd4f080830160 Mon Sep 17 00:00:00 2001 From: kirillov Date: Fri, 27 Feb 2015 10:07:33 +0000 Subject: [PATCH 2/5] Updating code to move FauxPublisher to public section --- examples/emm-notifications/README.md | 4 + .../work/emmnotifications/FauxPublisher.java | 89 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 examples/emm-notifications/README.md create mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/FauxPublisher.java diff --git a/examples/emm-notifications/README.md b/examples/emm-notifications/README.md new file mode 100644 index 0000000..ce120ce --- /dev/null +++ b/examples/emm-notifications/README.md @@ -0,0 +1,4 @@ +Play for Work EMM Push Notification +================================== + +Text goes here. diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/FauxPublisher.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/FauxPublisher.java new file mode 100644 index 0000000..ac42447 --- /dev/null +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/FauxPublisher.java @@ -0,0 +1,89 @@ +package com.google.android.work.emmnotifications; + +import com.google.android.work.pubsub.EmmPubsub; +import com.google.api.client.http.HttpResponseException; +import com.google.api.client.http.HttpStatusCodes; +import com.google.api.services.pubsub.Pubsub; +import com.google.api.services.pubsub.model.PublishRequest; +import com.google.api.services.pubsub.model.PubsubMessage; +import com.google.api.services.pubsub.model.Topic; +import com.google.common.collect.ImmutableList; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.logging.Logger; + +/** + * This is a faux publisher which can be used to simulate messages that would be normally sent by + * Play for Work API + * + * To run this sample code: + *
    + *
  1. Modify settings.properties or specify a different file via DEVELOPER_CONSOLE_SETTINGS + * environment variable
  2. + *
  3. Build a deploy jar using mvn clean compile assembly:single
  4. + *
  5. Execute it as + * java -cp target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar \ + * com.google.android.work.emmnotifications.FauxPublisher
  6. + *
+ + */ +public class FauxPublisher { + + private static final Logger LOG = + Logger.getLogger(FauxPublisher.class.getName()); + + public static void main(String[] args) + throws IOException, GeneralSecurityException { + + Pubsub pubsubClient = ServiceAccountConfiguration.createPubsubClient( + Settings.getSettings().getServiceAccountEmail(), + Settings.getSettings().getServiceAccountP12KeyPath()); + String topicName = Settings.getSettings().getTopicName(); + + try { + Topic topic = pubsubClient + .projects() + .topics() + .get(topicName) + .execute(); + + LOG.info("Topic " + topicName + " exists: " + topic.toPrettyString()); + } catch (HttpResponseException e) { + if (e.getStatusCode() == HttpStatusCodes.STATUS_CODE_NOT_FOUND) { + // Topic doesn't exist? + LOG.info("Topic " + topicName + " doesn't exists, creating it"); + pubsubClient + .projects() + .topics() + .create(topicName, new Topic()) + .execute(); + LOG.info("Topic " + topicName + " created"); + } + } + + ImmutableList.Builder listBuilder = ImmutableList.builder(); + + EmmPubsub.MdmPushNotification mdmPushNotification = EmmPubsub.MdmPushNotification.newBuilder() + .addProductApprovalEvent(EmmPubsub.ProductApprovalEvent.newBuilder() + .setApproved(false) + .setProductId("com.google.android.gms") + .setCommonEventInformation(EmmPubsub.MdmNotificationEnterpriseEventCommon.newBuilder() + .setEnterpriseId("12321321") + .setEventNotificationSentTimestamp("right now"))) + .build(); + + PublishRequest publishRequest = new PublishRequest() + .setMessages(ImmutableList.of(new PubsubMessage() + .encodeData(mdmPushNotification.toByteArray()))); + + LOG.info("Publishing a request: " + publishRequest.toPrettyString()); + + pubsubClient + .projects() + .topics() + .publish(topicName, publishRequest) + .execute(); + } + +} From 459648a4f774e67ed6594ceca72edd28e3b17e4b Mon Sep 17 00:00:00 2001 From: kirillov Date: Fri, 27 Feb 2015 10:11:04 +0000 Subject: [PATCH 3/5] Fixing endpoint settings --- README | 2 - .../google_settings.properties | 11 +- .../emm-notifications/settings.properties | 11 +- .../android/work/emmnotifications/Common.java | 61 ---------- .../work/emmnotifications/PushSubscriber.java | 37 ++++-- .../RetryHttpInitializerWrapper.java | 7 +- .../ServiceAccountConfiguration.java | 2 +- .../work/emmnotifications/Settings.java | 111 +++++++++++++++--- .../notpublic/FauxPublisher.java | 79 ------------- .../notpublic/PullSubscriber.java | 20 ++-- 10 files changed, 163 insertions(+), 178 deletions(-) delete mode 100644 README delete mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Common.java delete mode 100644 examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/FauxPublisher.java diff --git a/README b/README deleted file mode 100644 index 8d4bd1c..0000000 --- a/README +++ /dev/null @@ -1,2 +0,0 @@ -Play for Work -============= diff --git a/examples/emm-notifications/google_settings.properties b/examples/emm-notifications/google_settings.properties index 5bcaed4..36c9205 100644 --- a/examples/emm-notifications/google_settings.properties +++ b/examples/emm-notifications/google_settings.properties @@ -1,5 +1,12 @@ # NOT PUBLIC # Values for our internal developer console project (enterprise-cloud-pub-sub) - ServiceAccountEmail=368628613713-t4hf388f34tdn5lhpdcu1qqfgio01626@developer.gserviceaccount.com -ServiceAccountP12KeyFile=secret.p12 \ No newline at end of file + +# Download from here: https://pantheon.corp.google.com/project/enterprise-cloud-pub-sub/apiui/credential +ServiceAccountP12KeyFile=secret.p12 +ProjectName=enterprise-cloud-pub-sub +SubscriptionName=projects/enterprise-cloud-pub-sub/subscriptions/push-subscription +TopicName=projects/enterprise-cloud-pub-sub/topics/default-topic + +# Configured for the project mentioned above +PushEndpoint=e.r-k.co diff --git a/examples/emm-notifications/settings.properties b/examples/emm-notifications/settings.properties index 2bc061b..e165ba7 100644 --- a/examples/emm-notifications/settings.properties +++ b/examples/emm-notifications/settings.properties @@ -1,2 +1,11 @@ +# Create new service account at https://console.developers.google.com ServiceAccountEmail=changeme@gserviceaccount.com -ServiceAccountP12KeyFile=/path/to/key.p12 \ No newline at end of file +ServiceAccountP12KeyFile=/path/to/key.p12 + +# This will be the name of the service account you will create +ProjectName=sample-project-name +SubscriptionName=projects/sample-project-name/subscriptions/default +TopicName=projects/sample-project-name/topics/default + +# Define new push endpoint in developer console project +PushEndpoint=sample.push.endpoint diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Common.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Common.java deleted file mode 100644 index fed41d9..0000000 --- a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Common.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.google.android.work.emmnotifications; - -import com.google.api.services.pubsub.Pubsub; -import org.apache.commons.cli.*; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.logging.Logger; - -public class Common { - private static final Logger LOG = Logger.getLogger(Common.class.getName()); - - public static final String TOPIC_NAME = "topic_name"; - public static final String SUBSCRIPTION_NAME = "subscription_name"; - public static final String PROJECT_NAME = "project_name"; - - private static final String DEFAULT_PROJECT_NAME = "enterprise-cloud-pub-sub"; - - public static CommandLine getCommandLine(String[] args) throws ParseException { - Options options = new Options(); - - options.addOption("t", TOPIC_NAME, true, "Topic name"); - options.addOption("s", SUBSCRIPTION_NAME, true, "Subscription name"); - options.addOption("p", PROJECT_NAME, true, "Developer Console project name, e.g. cloud-pub-sub"); - - CommandLineParser parser = new GnuParser(); - CommandLine commandLine = parser.parse(options, args); - - // If project name is specified we will use default topic and subscription name - // If non-default topic and/or subscription name are specified, then project name makes no sense. - if (commandLine.hasOption(PROJECT_NAME) && - (commandLine.hasOption(TOPIC_NAME) || commandLine.hasOption(SUBSCRIPTION_NAME))) { - LOG.warning("Either --" + PROJECT_NAME - + " or combination of --" + TOPIC_NAME - + " and --" + SUBSCRIPTION_NAME - + " can be set"); - - System.exit(2); - } - - return commandLine; - } - - public static Pubsub makePubsubClient() throws IOException, GeneralSecurityException { - return ServiceAccountConfiguration.createPubsubClient( - Settings.getSettings().getServiceAccountEmail(), - Settings.getSettings().getServiceAccountP12KeyPath()); - } - - public static String getDefaultProjectName() { - return DEFAULT_PROJECT_NAME; - } - - public static String getDefaultTopicName() { - return "projects/" + getDefaultProjectName() + "/topics/hello-world-topic"; - } - - public static String getDefaultSubscriptionName() { - return "projects/" + getDefaultProjectName() + "/subscriptions/hello-world-sub"; - } -} diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/PushSubscriber.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/PushSubscriber.java index 6be719f..f0d9087 100644 --- a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/PushSubscriber.java +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/PushSubscriber.java @@ -2,6 +2,7 @@ import com.google.android.work.pubsub.EmmPubsub; import com.google.api.client.http.HttpResponseException; +import com.google.api.client.http.HttpStatusCodes; import com.google.api.client.json.JsonParser; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.pubsub.Pubsub; @@ -12,7 +13,6 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; -import org.apache.commons.cli.CommandLine; import java.io.IOException; import java.io.InputStreamReader; @@ -21,24 +21,39 @@ import java.util.logging.Logger; /** - * THIS WILL BE EXTERNAL CODE + * This is a sample subscriber code. To run it you need to have an SSL endpoint configured + * and run this code either on port 443 (update below) on the server backing this endpoint or + * configure a reverse proxy from port 443 to 8093. + * + * Details: [link will be here] + * + * To run this sample code: + *
    + *
  1. Modify settings.properties or specify a different file via DEVELOPER_CONSOLE_SETTINGS + * environment variable
  2. + *
  3. Build a deploy jar using mvn clean compile assembly:single
  4. + *
  5. Execute it as + * java -cp target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar \ + * com.google.android.work.emmnotifications.PushSubscriber
  6. + *
*/ public class PushSubscriber { - private static final String PUSH_ENDPOINT = "https://e.r-k.co"; + // this can be any port private static final int PORT = 8093; private static final Logger LOG = Logger.getLogger(PushSubscriber.class.getName()); public static final String MESSAGE_FIELD = "message"; public static void main(String[] args) throws Exception { - CommandLine commandLine = Common.getCommandLine(args); - Pubsub client = Common.makePubsubClient(); + Pubsub client = ServiceAccountConfiguration.createPubsubClient( + Settings.getSettings().getServiceAccountEmail(), + Settings.getSettings().getServiceAccountP12KeyPath()); // First we check if subscription actually exists for this subscription name. Subscription subscription = null; - String topicName = commandLine.getOptionValue(Common.TOPIC_NAME, Common.getDefaultTopicName()); - String subName = commandLine.getOptionValue(Common.SUBSCRIPTION_NAME, Common.getDefaultSubscriptionName()); + String topicName = Settings.getSettings().getTopicName(); + String subName = Settings.getSettings().getSubscriptionName(); LOG.info("Will be using topic name: " + topicName + ", subscription name: " + subName); @@ -54,7 +69,7 @@ public static void main(String[] args) throws Exception { } catch (HttpResponseException e) { // subscription not found - if (e.getStatusCode() == 404) { + if (e.getStatusCode() == HttpStatusCodes.STATUS_CODE_NOT_FOUND) { LOG.info("Subscription doesn't exist, will try to create " + subName); // Creating subscription @@ -65,7 +80,8 @@ public static void main(String[] args) throws Exception { .setTopic(topicName) // Name of the topic it subscribes to .setAckDeadlineSeconds(600) .setPushConfig(new PushConfig() - .setPushEndpoint(PUSH_ENDPOINT))) // FQDN with valid SSL certificate + // FQDN with valid SSL certificate + .setPushEndpoint(Settings.getSettings().getPushEndpoint()))) .execute(); LOG.info("Created: " + subscription.toPrettyString()); @@ -77,7 +93,8 @@ public static void main(String[] args) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(PORT), 0); server.createContext("/", new HttpHandler() { public void handle(HttpExchange httpExchange) throws IOException { - String rawRequest = CharStreams.toString(new InputStreamReader(httpExchange.getRequestBody())); + String rawRequest = CharStreams.toString( + new InputStreamReader(httpExchange.getRequestBody())); LOG.info("Raw request: " + rawRequest); try { diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/RetryHttpInitializerWrapper.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/RetryHttpInitializerWrapper.java index 564ccaa..56b1488 100644 --- a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/RetryHttpInitializerWrapper.java +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/RetryHttpInitializerWrapper.java @@ -1,7 +1,12 @@ package com.google.android.work.emmnotifications; import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.http.*; +import com.google.api.client.http.HttpBackOffIOExceptionHandler; +import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler; +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpRequestInitializer; +import com.google.api.client.http.HttpResponse; +import com.google.api.client.http.HttpUnsuccessfulResponseHandler; import com.google.api.client.util.ExponentialBackOff; import com.google.api.client.util.Sleeper; import com.google.common.base.Preconditions; diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/ServiceAccountConfiguration.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/ServiceAccountConfiguration.java index edda8d6..1124bb5 100644 --- a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/ServiceAccountConfiguration.java +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/ServiceAccountConfiguration.java @@ -14,7 +14,7 @@ import java.security.GeneralSecurityException; /** - * Create a Pubsub client with the service account. + * Creates a Pubsub client with the service account. */ public class ServiceAccountConfiguration { diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Settings.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Settings.java index 51f9aff..e0273ce 100644 --- a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Settings.java +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/Settings.java @@ -11,30 +11,71 @@ import static com.google.api.client.util.Preconditions.checkNotNull; /** - * Loads settings from settings.properties or file specified in DEVELOPER_CONSOLE_SETTINGS env variable. + * Loads settings from settings.properties or file specified in DEVELOPER_CONSOLE_SETTINGS + * env variable. */ public class Settings { private static final String EMAIL = "ServiceAccountEmail"; private static final String KEY = "ServiceAccountP12KeyFile"; + private static final String TOPIC_NAME = "TopicName"; + private static final String SUBSCRIPTION_NAME = "SubscriptionName"; + private static final String PROJECT_NAME = "ProjectName"; + private static final String PUSH_ENDPOINT = "PushEndpoint"; private static final String EMAIL_DEFAULT = "changeme@gserviceaccount.com"; private static final String KEY_DEFAULT = "/path/to/key.p12"; + private static final String TOPIC_NAME_DEFAULT = + "projects/sample-project-name/topics/default"; + private static final String SUBSCRIPTION_NAME_DEFAULT = + "projects/sample-project-name/subscriptions/default"; + private static final String PROJECT_NAME_DEFAULT = "sample-project-name"; + private static final String PUSH_ENDPOINT_DEFAULT = "sample.push.endpoint"; private static final Logger LOG = Logger.getLogger(Settings.class.getName()); public static final String SETTINGS_ENV_VAR_NAME = "DEVELOPER_CONSOLE_SETTINGS"; private static Settings settings = null; - private String serviceAccountEmail; - private String serviceAccountP12KeyPath; - - private Settings(String serviceAccountEmail, String serviceAccountP12KeyPath) { + // See https://cloud.google.com/pubsub/subscriber for more details + private final String topicName; + private final String subscriptionName; + + // Email address associated with your service account + // Obtain this from the "APIs & auth" -> "Credentials" + // section in the Google Developers Console: + // https://console.developers.google.com/ + // (and put the e-mail address into your system property obviously) + private final String serviceAccountEmail; + + // p12 file of your service account + // Download this file from "APIs & auth" -> "Credentials" + // section in the Google Developers Console: + // https://console.developers.google.com/ + private final String serviceAccountP12KeyPath; + + // Name of your developer console project + private final String projectName; + + // SSL WebHook enabled endpoint, see https://cloud.google.com/pubsub/prereqs#push_endpoints + private final String pushEndpoint; + + private Settings( + String serviceAccountEmail, + String serviceAccountP12KeyPath, + String topicName, + String subscriptionName, + String projectName, + String pushEndpoint) { this.serviceAccountEmail = serviceAccountEmail; this.serviceAccountP12KeyPath = serviceAccountP12KeyPath; + this.topicName = topicName; + this.subscriptionName = subscriptionName; + this.projectName = projectName; + this.pushEndpoint = pushEndpoint; } /** - * @return a singleton instance of Settings + * Returns a singleton instance of Settings * @throws IOException */ public static Settings getSettings() throws IOException { @@ -54,15 +95,41 @@ public static Settings getSettings() throws IOException { String email = properties.getProperty(EMAIL); String key = properties.getProperty(KEY); + String topicName = properties.getProperty(TOPIC_NAME); + String subscriptionName = properties.getProperty(SUBSCRIPTION_NAME); + String projectName = properties.getProperty(PROJECT_NAME); + String pushEndpoint = properties.getProperty(PUSH_ENDPOINT); + + verifyVariable(email, EMAIL, EMAIL_DEFAULT, settingsFilePath); + verifyVariable(key, KEY, KEY_DEFAULT, settingsFilePath); + verifyVariable(topicName, TOPIC_NAME, TOPIC_NAME_DEFAULT, settingsFilePath); + verifyVariable( + subscriptionName, + SUBSCRIPTION_NAME, + SUBSCRIPTION_NAME_DEFAULT, + settingsFilePath); + verifyVariable(projectName, PROJECT_NAME, PROJECT_NAME_DEFAULT, settingsFilePath); + verifyVariable(pushEndpoint, PUSH_ENDPOINT, PUSH_ENDPOINT_DEFAULT, settingsFilePath); + + return (settings = new Settings( + email, + key, + topicName, + subscriptionName, + projectName, + pushEndpoint)); + } - checkNotNull(email, EMAIL + " must be set in " + settingsFilePath); - checkArgument(!email.equals(EMAIL_DEFAULT), "You must specify non-default " + EMAIL + " in " + settingsFilePath); - - checkNotNull(key, KEY + " must be set in " + settingsFilePath); - checkArgument(!key.equals(KEY_DEFAULT), "You must specify non-default " + KEY + " in " + settingsFilePath); - - return (settings = new Settings(email, key)); - }; + private static void verifyVariable( + String variable, + String key, + String defaultValue, + String filePath) { + checkNotNull(variable, "%s must be set in %s", key, filePath); + checkArgument( + !variable.equals(defaultValue), + "You must specify non-default %s in %s", key, filePath); + } public String getServiceAccountEmail() { return serviceAccountEmail; @@ -71,4 +138,20 @@ public String getServiceAccountEmail() { public String getServiceAccountP12KeyPath() { return serviceAccountP12KeyPath; } + + public String getSubscriptionName() { + return subscriptionName; + } + + public String getTopicName() { + return topicName; + } + + public String getProjectName() { + return projectName; + } + + public String getPushEndpoint() { + return pushEndpoint; + } } diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/FauxPublisher.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/FauxPublisher.java deleted file mode 100644 index 1a3d906..0000000 --- a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/FauxPublisher.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.google.android.work.emmnotifications.notpublic; - -import com.google.android.work.emmnotifications.Common; -import com.google.android.work.pubsub.EmmPubsub; -import com.google.api.client.http.HttpResponseException; -import com.google.api.services.pubsub.Pubsub; -import com.google.api.services.pubsub.model.PublishRequest; -import com.google.api.services.pubsub.model.PubsubMessage; -import com.google.api.services.pubsub.model.Topic; -import com.google.common.collect.ImmutableList; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.ParseException; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.logging.Logger; - -/** - * ---- NOT PUBLIC CODE ---- - * - * This is a faux publisher which can be used to simulate messages that would be normally sent by - * Enterprise Server - */ -public class FauxPublisher { - - private static final Logger LOG = - Logger.getLogger(FauxPublisher.class.getName()); - - public static void main(String[] args) throws ParseException, IOException, GeneralSecurityException { - - CommandLine commandLine = Common.getCommandLine(args); - Pubsub pubsubClient = Common.makePubsubClient(); - String topicName = commandLine.getOptionValue(Common.TOPIC_NAME, Common.getDefaultTopicName()); - - try { - Topic topic = pubsubClient - .projects() - .topics() - .get(topicName) - .execute(); - - LOG.info("Topic " + topicName + " exists: " + topic.toPrettyString()); - } catch (HttpResponseException e) { - if (e.getStatusCode() == 404) { - // Topic doesn't exist? - LOG.info("Topic " + topicName + " doesn't exists, creating it"); - pubsubClient - .projects() - .topics() - .create(topicName, new Topic()) - .execute(); - LOG.info("Topic " + topicName + " created"); - } - } - - ImmutableList.Builder listBuilder = ImmutableList.builder(); - - EmmPubsub.MdmPushNotification mdmPushNotification = EmmPubsub.MdmPushNotification.newBuilder() - .addProductApprovalEvent(EmmPubsub.ProductApprovalEvent.newBuilder() - .setApproved(false) - .setProductId("com.google.android.gms") - .setCommonEventInformation(EmmPubsub.MdmNotificationEnterpriseEventCommon.newBuilder() - .setEnterpriseId("12321321") - .setEventNotificationSentTimestamp("right now"))) - .build(); - - pubsubClient - .projects() - .topics() - .publish( - topicName, - new PublishRequest() - .setMessages(ImmutableList.of( - new PubsubMessage() - .encodeData(mdmPushNotification.toByteArray())))) - .execute(); - } - -} diff --git a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/PullSubscriber.java b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/PullSubscriber.java index d8ec46b..3a26ce9 100644 --- a/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/PullSubscriber.java +++ b/examples/emm-notifications/src/main/java/com/google/android/work/emmnotifications/notpublic/PullSubscriber.java @@ -1,11 +1,16 @@ package com.google.android.work.emmnotifications.notpublic; -import com.google.android.work.emmnotifications.Common; +import com.google.android.work.emmnotifications.ServiceAccountConfiguration; +import com.google.android.work.emmnotifications.Settings; import com.google.api.client.http.HttpResponseException; import com.google.api.services.pubsub.Pubsub; -import com.google.api.services.pubsub.model.*; +import com.google.api.services.pubsub.model.AcknowledgeRequest; +import com.google.api.services.pubsub.model.PubsubMessage; +import com.google.api.services.pubsub.model.PullRequest; +import com.google.api.services.pubsub.model.PullResponse; +import com.google.api.services.pubsub.model.ReceivedMessage; +import com.google.api.services.pubsub.model.Subscription; import com.google.common.collect.ImmutableList; -import org.apache.commons.cli.CommandLine; import java.net.SocketTimeoutException; import java.util.logging.Logger; @@ -19,10 +24,11 @@ public class PullSubscriber { private static final Logger LOG = Logger.getLogger(PullSubscriber.class.getName()); public static void main(String[] args) throws Exception { - CommandLine commandLine = Common.getCommandLine(args); - Pubsub client = Common.makePubsubClient(); - String topicName = commandLine.getOptionValue(Common.TOPIC_NAME, Common.getDefaultTopicName()); - String subName = commandLine.getOptionValue(Common.SUBSCRIPTION_NAME, Common.getDefaultSubscriptionName()); + Pubsub client = ServiceAccountConfiguration.createPubsubClient( + Settings.getSettings().getServiceAccountEmail(), + Settings.getSettings().getServiceAccountP12KeyPath()); + String topicName = Settings.getSettings().getTopicName(); + String subName = Settings.getSettings().getSubscriptionName(); Subscription subscription = null; try { From 9eb987c3eff3653b07dc96005350dacfccff27fc Mon Sep 17 00:00:00 2001 From: kirillov Date: Fri, 27 Feb 2015 10:12:08 +0000 Subject: [PATCH 4/5] Removing tests --- .../work/emmnotifications/AppTest.java | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 examples/emm-notifications/src/test/java/com/google/android/work/emmnotifications/AppTest.java diff --git a/examples/emm-notifications/src/test/java/com/google/android/work/emmnotifications/AppTest.java b/examples/emm-notifications/src/test/java/com/google/android/work/emmnotifications/AppTest.java deleted file mode 100644 index fcaa15f..0000000 --- a/examples/emm-notifications/src/test/java/com/google/android/work/emmnotifications/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.google.android.work.emmnotifications; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} From c32b7cc9e1f551a95431b1284968d3baa7da67a4 Mon Sep 17 00:00:00 2001 From: kirillov Date: Fri, 27 Feb 2015 10:13:05 +0000 Subject: [PATCH 5/5] Removing run scripts --- examples/emm-notifications/run-publisher.sh | 6 ------ examples/emm-notifications/run-subscriber.sh | 7 ------- 2 files changed, 13 deletions(-) delete mode 100755 examples/emm-notifications/run-publisher.sh delete mode 100755 examples/emm-notifications/run-subscriber.sh diff --git a/examples/emm-notifications/run-publisher.sh b/examples/emm-notifications/run-publisher.sh deleted file mode 100755 index 8e45216..0000000 --- a/examples/emm-notifications/run-publisher.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -mvn clean compile assembly:single && \ -java -cp target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar \ - com.google.android.work.emmnotifications.notpublic.FauxPublisher \ - --topic_name=projects/enterprise-cloud-pub-sub/topics/hello-world-topic \ No newline at end of file diff --git a/examples/emm-notifications/run-subscriber.sh b/examples/emm-notifications/run-subscriber.sh deleted file mode 100755 index d0a46fc..0000000 --- a/examples/emm-notifications/run-subscriber.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -mvn clean compile assembly:single && \ -java -cp target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar \ - com.google.android.work.emmnotifications.PushSubscriber \ - --subscription_name=projects/enterprise-cloud-pub-sub/subscriptions/hello-world-push-subscription \ - --topic_name=projects/enterprise-cloud-pub-sub/topics/hello-world-topic \ No newline at end of file