diff --git a/iot/api-client/README.md b/iot/api-client/README.md
new file mode 100644
index 00000000000..2c61fe001a9
--- /dev/null
+++ b/iot/api-client/README.md
@@ -0,0 +1,38 @@
+# Cloud IoT Core Java Samples
+This folder contains Java samples that demonstrate an overview of the
+Google Cloud IoT Core platform.
+
+## Quickstart
+
+1. Install the gCloud CLI as described in [the device manager guide](https://cloud-dot-devsite.googleplex.com/iot/docs/device_manager_guide).
+2. Create a PubSub topic:
+
+ gcloud beta pubsub topics create projects/my-iot-project/topics/device-events
+
+3. Add the special account `cloud-iot@system.gserviceaccount.com` to that
+PubSub topic from the [Cloud Developer Console](https://console.cloud.google.com)
+or by using the helper script in the [/scripts](./scripts) folder.
+
+4. Create a registry:
+
+ gcloud alpha iot registries create my-registry \
+ --project=my-iot-project \
+ --region=us-central1 \
+ --pubsub-topic=projects/my-iot-project/topics/device-events
+
+5. Use the [`generate_keys.sh`](generate_keys.sh) script to generate your signing keys:
+
+ ./generate_keys.sh
+
+6. Create a device.
+
+ gcloud alpha iot devices create my-java-device \
+ --project=my-iot-project \
+ --region=us-central1 \
+ --registry=my-registry \
+ --public-key path=rsa_cert.pem,type=rs256
+
+7. Connect a sample device using the sample app in the [`mqtt_example`](./mqtt_example) folder.
+8. Learn how to manage devices programatically with the sample app in the
+`manager` folder.
+
diff --git a/iot/api-client/generate_keys.sh b/iot/api-client/generate_keys.sh
new file mode 100755
index 00000000000..e9beedc3dd6
--- /dev/null
+++ b/iot/api-client/generate_keys.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright 2017 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.
+
+openssl req -x509 -newkey rsa:2048 -keyout rsa_private.pem -nodes -out \
+ rsa_cert.pem -subj "/CN=unused"
+openssl ecparam -genkey -name prime256v1 -noout -out ec_private.pem
+openssl ec -in ec_private.pem -pubout -out ec_public.pem
+openssl pkcs8 -topk8 -inform PEM -outform DER -in rsa_private.pem \
+ -nocrypt > rsa_private_pkcs8
+openssl pkcs8 -topk8 -inform PEM -outform DER -in ec_private.pem \
+ -nocrypt > ec_private_pkcs8
diff --git a/iot/api-client/manager/README.md b/iot/api-client/manager/README.md
new file mode 100644
index 00000000000..c2036a5277c
--- /dev/null
+++ b/iot/api-client/manager/README.md
@@ -0,0 +1,43 @@
+# Cloud IoT Core Java Device Management example
+
+This sample app demonstrates device management for Google Cloud IoT Core.
+
+Note that before you can run the sample, you must configure a Google Cloud
+PubSub topic for Cloud IoT as described in [the parent README](../README.md).
+
+## Setup
+
+Manually install [the provided client library](https://cloud.google.com/iot/resources/java/cloud-iot-core-library.jar)
+for Cloud IoT Core to Maven:
+
+ mvn install:install-file -Dfile=cloud-iot-core-library.jar -DgroupId=com.google.apis \
+ -DartifactId=google-api-services-cloudiot -Dversion=v1beta1-rev20170418-1.22.0-SNAPSHOT \
+ -Dpackaging=jar
+
+Run the following command to install the libraries and build the sample with
+Maven:
+
+mvn clean compile assembly:single
+
+## Running the sample
+
+The following command summarizes the sample usage:
+
+ mvn exec:java \
+ -Dexec.mainClass="com.google.cloud.iot.examples.DeviceRegistryExample" \
+ -Dexec.args="-project_id=my-project-id \
+ -pubsub_topic=projects/my-project-id/topics/my-topic-id \
+ -ec_public_key_file=/path/to/ec_public.pem \
+ -rsa_certificate_file=/path/to/rsa_cert.pem"
+
+For example, if your project ID is `blue-jet-123`, your service account
+credentials are stored in your home folder in creds.json and you have generated
+your credentials using the shell script provided in the parent folder, you can
+run the sample as:
+
+ mvn exec:java \
+ -Dexec.mainClass="com.google.cloud.iot.examples.DeviceRegistryExample" \
+ -Dexec.args="-project_id=blue-jet-123 \
+ -pubsub_topic=projects/blue-jet-123/topics/device-events \
+ -ec_public_key_file=../ec_public.pem \
+ -rsa_certificate_file=../rsa_cert.pem"
diff --git a/iot/api-client/manager/pom.xml b/iot/api-client/manager/pom.xml
new file mode 100644
index 00000000000..100af9a82e2
--- /dev/null
+++ b/iot/api-client/manager/pom.xml
@@ -0,0 +1,79 @@
+
+
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.cloud.iot.examples; + +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.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.util.Charsets; +import com.google.api.services.cloudiot.v1beta1.CloudIot; +import com.google.api.services.cloudiot.v1beta1.CloudIotScopes; +import com.google.api.services.cloudiot.v1beta1.model.Device; +import com.google.api.services.cloudiot.v1beta1.model.DeviceConfig; +import com.google.api.services.cloudiot.v1beta1.model.DeviceConfigData; +import com.google.api.services.cloudiot.v1beta1.model.DeviceCredential; +import com.google.api.services.cloudiot.v1beta1.model.DeviceRegistry; +import com.google.api.services.cloudiot.v1beta1.model.ModifyCloudToDeviceConfigRequest; +import com.google.api.services.cloudiot.v1beta1.model.NotificationConfig; +import com.google.api.services.cloudiot.v1beta1.model.PublicKeyCredential; +import com.google.common.io.Files; + +import java.io.File; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.xml.bind.DatatypeConverter; + +/** + * Example of using Cloud IoT device manager API to administer devices, registries and projects. + * + *
This example uses the Device Manager API to create, retrieve, disable, list and delete Cloud + * IoT devices and registries, using both RSA and eliptic curve keys for authentication. + * + *
To start, follow the instructions on the Developer Guide at cloud.google.com/iot to create a + * service_account.json file and Cloud Pub/Sub topic as discussed in the guide. You will then need + * to point to the service_account.json file as described in + * https://developers.google.com/identity/protocols/application-default-credentials#howtheywork + * + *
Before running the example, we have to create private and public keys, as described in + * cloud.google.com/iot. Since we are interacting with the device manager, we will only use the + * public keys. The private keys are used to sign JWTs to authenticate devices. See the + * MQTT client example + * for more information. + * + *
Finally, compile and run the example with: + * + *
+ *
+ * $ mvn clean compile assembly:single
+ * $ mvn exec:java \
+ * -Dexec.mainClass="com.google.cloud.iot.examples.DeviceRegistryExample" \
+ * -Dexec.args="-project_id=my-project-id \
+ * -pubsub_topic=projects/my-project-id/topics/my-topic-id \
+ * -ec_public_key_file=/path/to/ec_public.pem \
+ * -rsa_certificate_file=/path/to/rsa_cert.pem"
+ *
+ *
+ */
+public class DeviceRegistryExample {
+ // Service for administering Cloud IoT Core devices, registries and projects.
+ private CloudIot service;
+ // Path to the project and location: "projects/my-project-id/locations/us-central1"
+ private String projectPath;
+ // Path to the registry: "projects/my-project-id/location/us-central1/registries/my-registry-id"
+ private String registryPath;
+
+ /** Construct a new registry with the given name and pubsub topic inside the given project. */
+ public DeviceRegistryExample(
+ String projectId, String location, String registryName, String pubsubTopicPath)
+ throws IOException, GeneralSecurityException {
+ GoogleCredential credential =
+ GoogleCredential.getApplicationDefault().createScoped(CloudIotScopes.all());
+ JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
+ HttpRequestInitializer init = new RetryHttpInitializerWrapper(credential);
+ service = new CloudIot(GoogleNetHttpTransport.newTrustedTransport(), jsonFactory, init);
+ projectPath = "projects/" + projectId + "/locations/" + location;
+ registryPath = projectPath + "/registries/" + registryName;
+
+ NotificationConfig notificationConfig = new NotificationConfig();
+ notificationConfig.setPubsubTopicName(pubsubTopicPath);
+
+ DeviceRegistry registry = new DeviceRegistry();
+ registry.setEventNotificationConfig(notificationConfig);
+ registry.setId(registryName);
+ service.projects().locations().registries().create(projectPath, registry).execute();
+ }
+
+ /** Delete this registry from Cloud IoT. */
+ public void delete() throws IOException {
+ System.out.println("Deleting: " + registryPath);
+ service.projects().locations().registries().delete(registryPath).execute();
+ }
+
+ /** Print all of the devices in this registry to standard out. */
+ public void listDevices() throws IOException {
+ ListThis is a valid way to construct a device, however until it is patched with a credential the
+ * device will not be able to connect to Cloud IoT.
+ */
+ public void createDeviceWithNoAuth(String deviceId) throws IOException {
+ createDevice(deviceId, new ArrayList 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.cloud.iot.examples;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+/** Command line options for the Device Manager example. */
+public class DeviceRegistryExampleOptions {
+ String projectId;
+ String pubsubTopic;
+ String ecPublicKeyFile = "ec_public.pem";
+ String rsaCertificateFile = "rsa_cert.pem";
+ String cloudRegion = "us-central1";
+
+ /** Construct an DeviceRegistryExampleOptions class from command line flags. */
+ public static DeviceRegistryExampleOptions fromFlags(String[] args) {
+ Options options = new Options();
+ // Required arguments
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("project_id")
+ .hasArg()
+ .desc("GCP cloud project name.")
+ .required()
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("pubsub_topic")
+ .hasArg()
+ .desc(
+ "Pub/Sub topic to create registry with, i.e. 'projects/project-id/topics/topic-id'")
+ .required()
+ .build());
+
+ // Optional arguments.
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("ec_public_key_file")
+ .hasArg()
+ .desc("Path to ES256 public key file.")
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("rsa_certificate_file")
+ .hasArg()
+ .desc("Path to RS256 certificate file.")
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("cloud_region")
+ .hasArg()
+ .desc("GCP cloud region.")
+ .build());
+
+ CommandLineParser parser = new DefaultParser();
+ CommandLine commandLine;
+ try {
+ commandLine = parser.parse(options, args);
+ DeviceRegistryExampleOptions res = new DeviceRegistryExampleOptions();
+
+ res.projectId = commandLine.getOptionValue("project_id");
+ res.pubsubTopic = commandLine.getOptionValue("pubsub_topic");
+
+ if (commandLine.hasOption("ec_public_key_file")) {
+ res.ecPublicKeyFile = commandLine.getOptionValue("ec_public_key_file");
+ }
+ if (commandLine.hasOption("rsa_certificate_file")) {
+ res.rsaCertificateFile = commandLine.getOptionValue("rsa_certificate_file");
+ }
+ if (commandLine.hasOption("cloud_region")) {
+ res.cloudRegion = commandLine.getOptionValue("cloud_region");
+ }
+ return res;
+ } catch (ParseException e) {
+ System.err.println(e.getMessage());
+ return null;
+ }
+ }
+}
diff --git a/iot/api-client/manager/src/main/java/com/google/cloud/iot/examples/RetryHttpInitializerWrapper.java b/iot/api-client/manager/src/main/java/com/google/cloud/iot/examples/RetryHttpInitializerWrapper.java
new file mode 100644
index 00000000000..71aad88ef33
--- /dev/null
+++ b/iot/api-client/manager/src/main/java/com/google/cloud/iot/examples/RetryHttpInitializerWrapper.java
@@ -0,0 +1,101 @@
+/**
+ * Copyright 2017, 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.cloud.iot.examples;
+
+import com.google.api.client.auth.oauth2.Credential;
+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;
+
+import java.io.IOException;
+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 {
+
+ /** A private logger. */
+ private static final Logger LOG = Logger.getLogger(RetryHttpInitializerWrapper.class.getName());
+
+ /** One minutes in milliseconds. */
+ private static final int ONE_MINUTE_MILLIS = 60 * 1000;
+
+ /**
+ * 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;
+
+ /**
+ * A constructor.
+ *
+ * @param wrappedCredential Credential which will be wrapped and used for providing auth header.
+ */
+ public RetryHttpInitializerWrapper(final Credential wrappedCredential) {
+ this(wrappedCredential, Sleeper.DEFAULT);
+ }
+
+ /**
+ * A protected constructor only for testing.
+ *
+ * @param wrappedCredential Credential which will be wrapped and used for providing auth header.
+ * @param sleeper Sleeper for easy testing.
+ */
+ RetryHttpInitializerWrapper(final Credential wrappedCredential, final Sleeper sleeper) {
+ this.wrappedCredential = Preconditions.checkNotNull(wrappedCredential);
+ this.sleeper = sleeper;
+ }
+
+ /** Initializes the given request. */
+ @Override
+ public final void initialize(final HttpRequest request) {
+ request.setReadTimeout(2 * ONE_MINUTE_MILLIS); // 2 minutes read timeout
+ final HttpUnsuccessfulResponseHandler backoffHandler =
+ new HttpBackOffUnsuccessfulResponseHandler(new ExponentialBackOff()).setSleeper(sleeper);
+ request.setInterceptor(wrappedCredential);
+ request.setUnsuccessfulResponseHandler(
+ new HttpUnsuccessfulResponseHandler() {
+ @Override
+ public boolean handleResponse(
+ final HttpRequest request, final HttpResponse response, final boolean supportsRetry)
+ throws IOException {
+ 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.
+ return true;
+ } else if (backoffHandler.handleResponse(request, response, supportsRetry)) {
+ // Otherwise, we defer to the judgment of our internal backoff handler.
+ LOG.info("Retrying " + request.getUrl().toString());
+ return true;
+ } else {
+ return false;
+ }
+ }
+ });
+ request.setIOExceptionHandler(
+ new HttpBackOffIOExceptionHandler(new ExponentialBackOff()).setSleeper(sleeper));
+ }
+}
diff --git a/iot/api-client/mqtt_example/README.md b/iot/api-client/mqtt_example/README.md
new file mode 100644
index 00000000000..969813330a9
--- /dev/null
+++ b/iot/api-client/mqtt_example/README.md
@@ -0,0 +1,52 @@
+# Cloud IoT Core Java MQTT example
+
+This sample app publishes data to Cloud Pub/Sub using the MQTT bridge provided
+as part of Google Cloud IoT Core.
+
+Note that before you can run the sample, you must configure a Google Cloud
+PubSub topic for Cloud IoT Core and register a device as described in the
+[parent README](../README.md).
+
+## Setup
+
+Run the following command to install the dependencies using Maven:
+
+ mvn clean compile
+
+## Running the sample
+
+The following command summarizes the sample usage:
+
+ mvn exec:java \
+ -Dexec.mainClass="com.google.cloud.iot.examples.MqttExample" \
+ -Dexec.args="-project_id=my-iot-project \
+ -registry_id=my-registry \
+ -device_id=my-device \
+ -private_key_file=rsa_private_pkcs8 \
+ -algorithm=RS256"
+
+For example, if your project ID is `blue-jet-123`, your service account
+credentials are stored in your home folder in creds.json and you have generated
+your credentials using the [`generate_keys.sh`](../generate_keys.sh) script
+provided in the parent folder, you can run the sample as:
+
+ mvn exec:java \
+ -Dexec.mainClass="com.google.cloud.iot.examples.MqttExample" \
+ -Dexec.args="-project_id=blue-jet-123 \
+ -registry_id=my-registry \
+ -device_id=my-device \
+ -private_key_file=../rsa_private_pkcs8 \
+ -algorithm=RS256"
+
+## Reading the messages written by the sample client
+
+1. Create a subscription to your topic.
+
+ gcloud beta pubsub subscriptions create \
+ projects/your-project-id/subscriptions/my-subscription \
+ --topic device-events
+
+2. Read messages published to the topic
+
+ gcloud beta pubsub subscriptions pull --auto-ack \
+ projects/my-iot-project/subscriptions/my-subscription
diff --git a/iot/api-client/mqtt_example/pom.xml b/iot/api-client/mqtt_example/pom.xml
new file mode 100644
index 00000000000..09b95f4966e
--- /dev/null
+++ b/iot/api-client/mqtt_example/pom.xml
@@ -0,0 +1,54 @@
+ This example connects to Google Cloud IoT Core via MQTT, using a JWT for device
+ * authentication. After connecting, by default the device publishes 100 messages to
+ * the device's MQTT topic at a rate of one per second, and then exits.
+ *
+ * To run this example, first create your credentials and register your device as
+ * described in the README located in the sample's parent folder.
+ *
+ * After you have registered your device and generated your credentials, compile and
+ * run with the corresponding algorithm flag, for example:
+ *
+ *
+ * $ mvn compile
+ * $ mvn exec:java -Dexec.mainClass="com.google.cloud.iot.examples.MqttExample" \
+ * -Dexec.args="-project_id=my-project-id \
+ * -registry_id=my-registry-id \
+ * -device_id=my-device-id \
+ * -private_key_file=/path/to/private_pkcs8 \
+ * -algorithm=RS256"
+ *
+ */
+public class MqttExample {
+ /** Load a PKCS8 encoded keyfile from the given path. */
+ private static PrivateKey loadKeyFile(String filename, String algorithm) throws Exception {
+ byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
+ PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory kf = KeyFactory.getInstance(algorithm);
+ return kf.generatePrivate(spec);
+ }
+
+ /** Create a Cloud IoT Core JWT for the given project id, signed with the given private key. */
+ private static String createJwt(String projectId, String privateKeyFile, String algorithm)
+ throws Exception {
+ DateTime now = new DateTime();
+ // Create a JWT to authenticate this device. The device will be disconnected after the token
+ // expires, and will have to reconnect with a new token. The audience field should always be set
+ // to the GCP project id.
+ JwtBuilder jwtBuilder =
+ Jwts.builder()
+ .setIssuedAt(now.toDate())
+ .setExpiration(now.plusMinutes(20).toDate())
+ .setAudience(projectId);
+
+ if (algorithm.equals("RS256")) {
+ PrivateKey privateKey = loadKeyFile(privateKeyFile, "RSA");
+ return jwtBuilder.signWith(SignatureAlgorithm.RS256, privateKey).compact();
+ } else if (algorithm.equals("ES256")) {
+ PrivateKey privateKey = loadKeyFile(privateKeyFile, "EC");
+ return jwtBuilder.signWith(SignatureAlgorithm.ES256, privateKey).compact();
+ } else {
+ throw new IllegalArgumentException(
+ "Invalid algorithm " + algorithm + ". Should be one of 'RS256' or 'ES256'.");
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ MqttExampleOptions options = MqttExampleOptions.fromFlags(args);
+ if (options == null) {
+ // Could not parse.
+ System.exit(1);
+ }
+
+ // Build the connection string for Google's Cloud IoT Core MQTT server. Only SSL
+ // connections are accepted. For server authentication, the JVM's root certificates
+ // are used.
+ String mqttServerAddress =
+ String.format("ssl://%s:%s", options.mqttBridgeHostname, options.mqttBridgePort);
+
+ // Create our MQTT client. The mqttClientId is a unique string that identifies this device. For
+ // Google Cloud IoT Core, it must be in the format below.
+ String mqttClientId =
+ String.format(
+ "projects/%s/locations/%s/registries/%s/devices/%s",
+ options.projectId, options.cloudRegion, options.registryId, options.deviceId);
+
+ MqttConnectOptions connectOptions = new MqttConnectOptions();
+ // Note that the the Google Cloud IoT Core only supports MQTT 3.1.1, and Paho requires that we
+ // explictly set this. If you don't set MQTT version, the server will immediately close its
+ // connection to your device.
+ connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
+
+ // With Google Cloud IoT Core, the username field is ignored, however it must be set for the
+ // Paho client library to send the password field. The password field is used to transmit a JWT
+ // to authorize the device.
+ connectOptions.setUserName("unused");
+ connectOptions.setPassword(
+ createJwt(options.projectId, options.privateKeyFile, options.algorithm).toCharArray());
+
+ // Create a client, and connect to the Google MQTT bridge.
+ MqttClient client = new MqttClient(mqttServerAddress, mqttClientId, new MemoryPersistence());
+ client.connect(connectOptions);
+
+ // The MQTT topic that this device will publish telemetry data to. The MQTT topic name is
+ // required to be in the format below. Note that this is not the same as the device registry's
+ // Cloud Pub/Sub topic.
+ String mqttTopic = String.format("/devices/%s/events", options.deviceId);
+
+ // Publish numMessages messages to the MQTT bridge, at a rate of 1 per second.
+ for (int i = 1; i <= options.numMessages; ++i) {
+ String payload = String.format("%s/%s-payload-%d", options.registryId, options.deviceId, i);
+ System.out.format("Publishing message %d/%d: '%s'\n", i, options.numMessages, payload);
+
+ // Publish "payload" to the MQTT topic. qos=1 means at least once delivery. Cloud IoT Core
+ // also supports qos=0 for at most once delivery.
+ MqttMessage message = new MqttMessage(payload.getBytes());
+ message.setQos(1);
+ client.publish(mqttTopic, message);
+ Thread.sleep(1000);
+ }
+ // Disconnect the client and finish the run.
+ client.disconnect();
+ System.out.println("Finished loop successfully. Goodbye!");
+ }
+}
diff --git a/iot/api-client/mqtt_example/src/main/java/com/google/cloud/iot/examples/MqttExampleOptions.java b/iot/api-client/mqtt_example/src/main/java/com/google/cloud/iot/examples/MqttExampleOptions.java
new file mode 100644
index 00000000000..472ee15bb47
--- /dev/null
+++ b/iot/api-client/mqtt_example/src/main/java/com/google/cloud/iot/examples/MqttExampleOptions.java
@@ -0,0 +1,127 @@
+package com.google.cloud.iot.examples;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+/** Command line options for the MQTT example. */
+public class MqttExampleOptions {
+ String projectId;
+ String registryId;
+ String deviceId;
+ String privateKeyFile;
+ String algorithm;
+ String cloudRegion = "us-central1";
+ int numMessages = 100;
+ String mqttBridgeHostname = "mqtt.googleapis.com";
+ short mqttBridgePort = 8883;
+
+ /** Construct an MqttExampleOptions class from command line flags. */
+ public static MqttExampleOptions fromFlags(String[] args) {
+ Options options = new Options();
+ // Required arguments
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("project_id")
+ .hasArg()
+ .desc("GCP cloud project name.")
+ .required()
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("registry_id")
+ .hasArg()
+ .desc("Cloud IoT Core registry id.")
+ .required()
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("device_id")
+ .hasArg()
+ .desc("Cloud IoT Core device id.")
+ .required()
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("private_key_file")
+ .hasArg()
+ .desc("Path to private key file.")
+ .required()
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("algorithm")
+ .hasArg()
+ .desc("Encryption algorithm to use to generate the JWT. Either 'RS256' or 'ES256'.")
+ .required()
+ .build());
+
+ // Optional arguments.
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("cloud_region")
+ .hasArg()
+ .desc("GCP cloud region.")
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(Number.class)
+ .longOpt("num_messages")
+ .hasArg()
+ .desc("Number of messages to publish.")
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(String.class)
+ .longOpt("mqtt_bridge_hostname")
+ .hasArg()
+ .desc("MQTT bridge hostname.")
+ .build());
+ options.addOption(
+ Option.builder()
+ .type(Number.class)
+ .longOpt("mqtt_bridge_port")
+ .hasArg()
+ .desc("MQTT bridge port.")
+ .build());
+
+ CommandLineParser parser = new DefaultParser();
+ CommandLine commandLine;
+ try {
+ commandLine = parser.parse(options, args);
+ MqttExampleOptions res = new MqttExampleOptions();
+
+ res.projectId = commandLine.getOptionValue("project_id");
+ res.registryId = commandLine.getOptionValue("registry_id");
+ res.deviceId = commandLine.getOptionValue("device_id");
+ res.privateKeyFile = commandLine.getOptionValue("private_key_file");
+ res.algorithm = commandLine.getOptionValue("algorithm");
+ if (commandLine.hasOption("cloud_region")) {
+ res.cloudRegion = commandLine.getOptionValue("cloud_region");
+ }
+ if (commandLine.hasOption("num_messages")) {
+ res.numMessages = ((Number) commandLine.getParsedOptionValue("num_messages")).intValue();
+ }
+ if (commandLine.hasOption("mqtt_bridge_hostname")) {
+ res.mqttBridgeHostname = commandLine.getOptionValue("mqtt_bridge_hostname");
+ }
+ if (commandLine.hasOption("mqtt_bridge_port")) {
+ res.mqttBridgePort =
+ ((Number) commandLine.getParsedOptionValue("mqtt_bridge_port")).shortValue();
+ }
+ return res;
+ } catch (ParseException e) {
+ System.err.println(e.getMessage());
+ return null;
+ }
+ }
+}
diff --git a/iot/api-client/scripts/README.rst b/iot/api-client/scripts/README.rst
new file mode 100644
index 00000000000..2d48c4a9aba
--- /dev/null
+++ b/iot/api-client/scripts/README.rst
@@ -0,0 +1,115 @@
+.. This file is automatically generated. Do not edit this file directly.
+
+Google Cloud IoT Core Python Samples
+===============================================================================
+
+This directory contains samples for Google Cloud IoT Core. `Google Cloud IoT Core`_ is a fully-managed, globally distributed solution for managing devices and sending / receiving messages from devices. Set the `GOOGLE_CLOUD_PROJECT` environment variable and call the script with your topic ID.
+
+
+
+
+.. _Google Cloud IoT Core: https://cloud.google.com/iot/
+
+Setup
+-------------------------------------------------------------------------------
+
+
+Authentication
+++++++++++++++
+
+Authentication is typically done through `Application Default Credentials`_,
+which means you do not have to change the code to authenticate as long as
+your environment has credentials. You have a few options for setting up
+authentication:
+
+#. When running locally, use the `Google Cloud SDK`_
+
+ .. code-block:: bash
+
+ gcloud auth application-default login
+
+
+#. When running on App Engine or Compute Engine, credentials are already
+ set-up. However, you may need to configure your Compute Engine instance
+ with `additional scopes`_.
+
+#. You can create a `Service Account key file`_. This file can be used to
+ authenticate to Google Cloud Platform services from any environment. To use
+ the file, set the ``GOOGLE_APPLICATION_CREDENTIALS`` environment variable to
+ the path to the key file, for example:
+
+ .. code-block:: bash
+
+ export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account.json
+
+.. _Application Default Credentials: https://cloud.google.com/docs/authentication#getting_credentials_for_server-centric_flow
+.. _additional scopes: https://cloud.google.com/compute/docs/authentication#using
+.. _Service Account key file: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount
+
+Install Dependencies
+++++++++++++++++++++
+
+#. Install `pip`_ and `virtualenv`_ if you do not already have them.
+
+#. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+.
+
+ .. code-block:: bash
+
+ $ virtualenv env
+ $ source env/bin/activate
+
+#. Install the dependencies needed to run the samples.
+
+ .. code-block:: bash
+
+ $ pip install -r requirements.txt
+
+.. _pip: https://pip.pypa.io/
+.. _virtualenv: https://virtualenv.pypa.io/
+
+Samples
+-------------------------------------------------------------------------------
+
+PubSub helper
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+
+To run this sample:
+
+.. code-block:: bash
+
+ $ python iam.py
+
+ usage: iam.py [-h] topic_name
+
+ This application demonstrates how programatically grant access to the
+ Cloud IoT Core service account on a given PubSub topic.
+
+ For more information, see https://cloud.google.com/iot.
+
+ positional arguments:
+ topic_name The PubSub topic to grant Cloud IoT Core access to
+
+ optional arguments:
+ -h, --help show this help message and exit
+
+
+
+
+The client library
+-------------------------------------------------------------------------------
+
+This sample uses the `Google Cloud Client Library for Python`_.
+You can read the documentation for more details on API usage and use GitHub
+to `browse the source`_ and `report issues`_.
+
+.. Google Cloud Client Library for Python:
+ https://googlecloudplatform.github.io/google-cloud-python/
+.. browse the source:
+ https://github.com/GoogleCloudPlatform/google-cloud-python
+.. report issues:
+ https://github.com/GoogleCloudPlatform/google-cloud-python/issues
+
+
+.. _Google Cloud SDK: https://cloud.google.com/sdk/
\ No newline at end of file
diff --git a/iot/api-client/scripts/README.rst.in b/iot/api-client/scripts/README.rst.in
new file mode 100644
index 00000000000..dfd077ff41b
--- /dev/null
+++ b/iot/api-client/scripts/README.rst.in
@@ -0,0 +1,22 @@
+# This file is used to generate README.rst
+
+product:
+ name: Google Cloud IoT Core
+ short_name: Cloud IoT Core
+ url: https://cloud.google.com/iot/
+ description: >
+ `Google Cloud IoT Core`_ is a fully-managed, globally distributed solution
+ for managing devices and sending / receiving messages from devices. Set the
+ `GOOGLE_CLOUD_PROJECT` environment variable and call the script with your
+ topic ID.
+
+setup:
+- auth
+- install_deps
+
+samples:
+- name: PubSub helper
+ file: iam.py
+ show_help: true
+
+cloud_client_library: true
diff --git a/iot/api-client/scripts/iam.py b/iot/api-client/scripts/iam.py
new file mode 100644
index 00000000000..43cd838b78c
--- /dev/null
+++ b/iot/api-client/scripts/iam.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright 2017 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.
+
+"""This application demonstrates how programatically grant access to the
+Cloud IoT Core service account on a given PubSub topic.
+
+For more information, see https://cloud.google.com/iot.
+"""
+
+import argparse
+
+from google.cloud import pubsub
+
+
+def set_topic_policy(topic_name):
+ """Sets the IAM policy for a topic for Cloud IoT Core."""
+ pubsub_client = pubsub.Client()
+ topic = pubsub_client.topic(topic_name)
+ policy = topic.get_iam_policy()
+
+ # Add a group as publishers.
+ publishers = policy.get('roles/pubsub.publisher', [])
+ publishers.append(policy.service_account(
+ 'cloud-iot@system.gserviceaccount.com'))
+ policy['roles/pubsub.publisher'] = publishers
+
+ # Set the policy
+ topic.set_iam_policy(policy)
+
+ print('IAM policy for topic {} set.'.format(topic.name))
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter
+ )
+
+ subparsers = parser.add_argument(dest='topic_name',
+ help='The PubSub topic to grant Cloud IoT Core access to')
+
+ args = parser.parse_args()
+
+ set_topic_policy(args.topic_name)
diff --git a/iot/api-client/scripts/requirements.txt b/iot/api-client/scripts/requirements.txt
new file mode 100644
index 00000000000..1412eed3dca
--- /dev/null
+++ b/iot/api-client/scripts/requirements.txt
@@ -0,0 +1 @@
+google-cloud-pubsub==0.25.0