├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ ├── documentation.yml │ └── feature-request.yml └── workflows │ ├── ci.yml │ ├── closed-issue-message.yml │ ├── handle-stale-discussions.yml │ └── stale_issue.yml ├── .gitignore ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── aws-iot-device-sdk-java-samples ├── pom.xml ├── samples-pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── amazonaws │ │ └── services │ │ └── iot │ │ └── client │ │ └── sample │ │ ├── pubSub │ │ ├── NonBlockingPublishListener.java │ │ ├── PublishSubscribeSample.java │ │ └── TestTopicListener.java │ │ ├── sampleUtil │ │ ├── CommandArguments.java │ │ ├── PrivateKeyReader.java │ │ └── SampleUtil.java │ │ ├── shadow │ │ ├── ConnectedWindow.java │ │ └── ShadowSample.java │ │ └── shadowEcho │ │ ├── ShadowEchoSample.java │ │ └── Thing.java │ └── resources │ └── com │ └── amazonaws │ └── services │ └── iot │ └── client │ └── sample │ └── sampleUtil │ └── aws-iot-sdk-samples.properties ├── aws-iot-device-sdk-java ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── amazonaws │ │ └── services │ │ └── iot │ │ └── client │ │ ├── AWSIotConfig.java │ │ ├── AWSIotConnectionStatus.java │ │ ├── AWSIotDevice.java │ │ ├── AWSIotDeviceErrorCode.java │ │ ├── AWSIotDeviceProperty.java │ │ ├── AWSIotException.java │ │ ├── AWSIotMessage.java │ │ ├── AWSIotMqttClient.java │ │ ├── AWSIotQos.java │ │ ├── AWSIotTimeoutException.java │ │ ├── AWSIotTopic.java │ │ ├── auth │ │ ├── Credentials.java │ │ ├── CredentialsProvider.java │ │ └── StaticCredentialsProvider.java │ │ ├── core │ │ ├── AbstractAwsIotClient.java │ │ ├── AwsIotCompletion.java │ │ ├── AwsIotConnection.java │ │ ├── AwsIotConnectionCallback.java │ │ ├── AwsIotConnectionType.java │ │ ├── AwsIotMessageCallback.java │ │ ├── AwsIotRetryableException.java │ │ ├── AwsIotRuntimeException.java │ │ ├── AwsIotTlsConnection.java │ │ ├── AwsIotTopicCallback.java │ │ └── AwsIotWebsocketConnection.java │ │ ├── mqtt │ │ ├── AwsIotMqttClientListener.java │ │ ├── AwsIotMqttConnection.java │ │ ├── AwsIotMqttConnectionListener.java │ │ └── AwsIotMqttMessageListener.java │ │ ├── shadow │ │ ├── AbstractAwsIotDevice.java │ │ ├── AwsIotDeviceCommand.java │ │ ├── AwsIotDeviceCommandAckListener.java │ │ ├── AwsIotDeviceCommandManager.java │ │ ├── AwsIotDeviceDeltaListener.java │ │ ├── AwsIotDeviceReportMessage.java │ │ ├── AwsIotDeviceSyncMessage.java │ │ ├── AwsIotJsonDeserializer.java │ │ └── AwsIotJsonSerializer.java │ │ └── util │ │ ├── AwsIotTlsSocketFactory.java │ │ └── AwsIotWebSocketUrlSigner.java │ └── test │ └── java │ └── com │ └── amazonaws │ └── services │ └── iot │ └── client │ ├── AWSIotDeviceErrorCodeTest.java │ ├── AWSIotDeviceIntegrationTest.java │ ├── AWSIotMessageTest.java │ ├── AWSIotMqttClientIntegrationTest.java │ ├── AWSIotMqttClientIntegrationUtil.java │ ├── AWSIotQosTest.java │ ├── CredentialUtil.java │ ├── TestDevice.java │ ├── TestDeviceNotifier.java │ ├── TestTopic.java │ ├── auth │ ├── core │ ├── AbstractAwsIotClientTest.java │ ├── AwsIotCompletionTest.java │ ├── AwsIotConnectionTest.java │ └── AwsIotWebsocketConnectionTest.java │ ├── mqtt │ ├── AwsIotMqttClientListenerTest.java │ ├── AwsIotMqttConnectionListenerTest.java │ ├── AwsIotMqttConnectionTest.java │ └── AwsIotMqttMessageListenerTest.java │ ├── shadow │ ├── AbstractAwsIotDeviceTest.java │ ├── AwsIotDeviceCommandManagerTest.java │ ├── AwsIotDeviceCommandTest.java │ ├── AwsIotDeviceDeltaListenerTest.java │ ├── AwsIotDeviceReportMessageTest.java │ └── AwsIotDeviceSyncMessageTest.java │ ├── system_props_mutualAuth.properties │ ├── system_props_websocket.properties │ └── util │ ├── AwsIotTlsSocketFactoryTest.java │ └── AwsIotWebSocketUrlSignerTest.java ├── codebuild └── cd │ ├── promote-release.yml │ ├── test-version-exists.sh │ └── test-version-exists.yml └── pom.xml /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🐛 Bug Report" 3 | description: Report a bug 4 | title: "(short issue description)" 5 | labels: [bug, needs-triage] 6 | assignees: [] 7 | body: 8 | - type: textarea 9 | id: description 10 | attributes: 11 | label: Describe the bug 12 | description: What is the problem? A clear and concise description of the bug. 13 | validations: 14 | required: true 15 | - type: textarea 16 | id: expected 17 | attributes: 18 | label: Expected Behavior 19 | description: | 20 | What did you expect to happen? 21 | validations: 22 | required: true 23 | - type: textarea 24 | id: current 25 | attributes: 26 | label: Current Behavior 27 | description: | 28 | What actually happened? 29 | 30 | Please include full errors, uncaught exceptions, stack traces, and relevant logs. 31 | If service responses are relevant, please include wire logs. 32 | validations: 33 | required: true 34 | - type: textarea 35 | id: reproduction 36 | attributes: 37 | label: Reproduction Steps 38 | description: | 39 | Provide a self-contained, concise snippet of code that can be used to reproduce the issue. 40 | For more complex issues provide a repo with the smallest sample that reproduces the bug. 41 | 42 | Avoid including business logic or unrelated code, it makes diagnosis more difficult. 43 | The code sample should be an SSCCE. See http://sscce.org/ for details. In short, please provide a code sample that we can copy/paste, run and reproduce. 44 | validations: 45 | required: true 46 | - type: textarea 47 | id: solution 48 | attributes: 49 | label: Possible Solution 50 | description: | 51 | Suggest a fix/reason for the bug 52 | validations: 53 | required: false 54 | - type: textarea 55 | id: context 56 | attributes: 57 | label: Additional Information/Context 58 | description: | 59 | Anything else that might be relevant for troubleshooting this bug. Providing context helps us come up with a solution that is most useful in the real world. 60 | validations: 61 | required: false 62 | - type: input 63 | id: sdk-version 64 | attributes: 65 | label: SDK version used 66 | validations: 67 | required: true 68 | - type: input 69 | id: environment 70 | attributes: 71 | label: Environment details (OS name and version, etc.) 72 | validations: 73 | required: true 74 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | blank_issues_enabled: false 3 | contact_links: 4 | - name: 💬 General Question 5 | url: https://github.com/aws/aws-iot-device-sdk-java/discussions/categories/q-a 6 | about: Please ask and answer questions as a discussion thread 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "📕 Documentation Issue" 3 | description: Report an issue in the API Reference documentation or Developer Guide 4 | title: "(short issue description)" 5 | labels: [documentation, needs-triage] 6 | assignees: [] 7 | body: 8 | - type: textarea 9 | id: description 10 | attributes: 11 | label: Describe the issue 12 | description: A clear and concise description of the issue. 13 | validations: 14 | required: true 15 | 16 | - type: textarea 17 | id: links 18 | attributes: 19 | label: Links 20 | description: | 21 | Include links to affected documentation page(s). 22 | validations: 23 | required: true 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | name: 🚀 Feature Request 4 | description: Suggest an idea for this project 5 | title: "(short issue description)" 6 | labels: [feature-request, needs-triage] 7 | assignees: [] 8 | body: 9 | - type: textarea 10 | id: description 11 | attributes: 12 | label: Describe the feature 13 | description: A clear and concise description of the feature you are proposing. 14 | validations: 15 | required: true 16 | - type: textarea 17 | id: use-case 18 | attributes: 19 | label: Use Case 20 | description: | 21 | Why do you need this feature? For example: "I'm always frustrated when..." 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: solution 26 | attributes: 27 | label: Proposed Solution 28 | description: | 29 | Suggest how to implement the addition or change. Please include prototype/workaround/sketch/reference implementation. 30 | validations: 31 | required: false 32 | - type: textarea 33 | id: other 34 | attributes: 35 | label: Other Information 36 | description: | 37 | Any alternative solutions or features you considered, a more detailed explanation, stack traces, related issues, links for context, etc. 38 | validations: 39 | required: false 40 | - type: checkboxes 41 | id: ack 42 | attributes: 43 | label: Acknowledgements 44 | options: 45 | - label: I may be able to implement this feature request 46 | required: false 47 | - label: This feature might incur a breaking change 48 | required: false 49 | - type: input 50 | id: sdk-version 51 | attributes: 52 | label: SDK version used 53 | validations: 54 | required: true 55 | - type: input 56 | id: environment 57 | attributes: 58 | label: Environment details (OS name and version, etc.) 59 | validations: 60 | required: true 61 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - '!main' 8 | 9 | env: 10 | BUILDER_VERSION: v0.9.14 11 | BUILDER_SOURCE: releases 12 | BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net 13 | PACKAGE_NAME: aws-iot-device-sdk-java 14 | RUN: ${{ github.run_id }}-${{ github.run_number }} 15 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 16 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 17 | AWS_DEFAULT_REGION: us-east-1 18 | 19 | jobs: 20 | java-compat: 21 | runs-on: ubuntu-20.04 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | version: 26 | - 8 27 | - 11 28 | - 17 29 | steps: 30 | - name: Checkout Sources 31 | uses: actions/checkout@v2 32 | - name: Setup Java 33 | uses: actions/setup-java@v2 34 | with: 35 | distribution: temurin 36 | java-version: ${{ matrix.version }} 37 | cache: maven 38 | - name: Build ${{ env.PACKAGE_NAME }} + consumers 39 | run: | 40 | java -version 41 | mvn -B test 42 | -------------------------------------------------------------------------------- /.github/workflows/closed-issue-message.yml: -------------------------------------------------------------------------------- 1 | name: Closed Issue Message 2 | on: 3 | issues: 4 | types: [closed] 5 | jobs: 6 | auto_comment: 7 | runs-on: ubuntu-latest 8 | permissions: 9 | issues: write 10 | steps: 11 | - uses: aws-actions/closed-issue-message@v1 12 | with: 13 | # These inputs are both required 14 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 15 | message: | 16 | This issue is now closed. Comments on closed issues are hard for our team to see. 17 | If you need more assistance, please open a new issue that references this one. 18 | -------------------------------------------------------------------------------- /.github/workflows/handle-stale-discussions.yml: -------------------------------------------------------------------------------- 1 | name: HandleStaleDiscussions 2 | on: 3 | schedule: 4 | - cron: '0 */4 * * *' 5 | discussion_comment: 6 | types: [created] 7 | 8 | jobs: 9 | handle-stale-discussions: 10 | name: Handle stale discussions 11 | runs-on: ubuntu-latest 12 | permissions: 13 | discussions: write 14 | steps: 15 | - name: Stale discussions action 16 | uses: aws-github-ops/handle-stale-discussions@v1 17 | env: 18 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 19 | -------------------------------------------------------------------------------- /.github/workflows/stale_issue.yml: -------------------------------------------------------------------------------- 1 | name: "Close stale issues" 2 | 3 | # Controls when the action will run. 4 | on: 5 | schedule: 6 | - cron: "0 0 * * *" 7 | 8 | jobs: 9 | cleanup: 10 | runs-on: ubuntu-latest 11 | name: Stale issue job 12 | permissions: 13 | issues: write 14 | pull-requests: write 15 | steps: 16 | - uses: aws-actions/stale-issue-cleanup@v3 17 | with: 18 | # Setting messages to an empty string will cause the automation to skip 19 | # that category 20 | ancient-issue-message: Greetings! Sorry to say but this is a very old issue that is probably not getting as much attention as it deserves. We encourage you to try V2 and if you find that this is still a problem, please feel free to open a new issue there. 21 | stale-issue-message: Greetings! It looks like this issue hasn’t been active in longer than a week. Because it has been longer than a week since the last update on this, and in the absence of more information, we will be closing this issue soon. If you find that this is still a problem, please feel free to provide a comment or add an upvote to prevent automatic closure, or if the issue is already closed, please feel free to open a new one, also please try V2 as this might be solved there too. 22 | stale-pr-message: Greetings! It looks like this PR hasn’t been active in longer than a week, add a comment or an upvote to prevent automatic closure, or if the issue is already closed, please feel free to open a new one. 23 | 24 | # These labels are required 25 | stale-issue-label: closing-soon 26 | exempt-issue-label: automation-exempt 27 | stale-pr-label: closing-soon 28 | exempt-pr-label: pr/needs-review 29 | response-requested-label: response-requested 30 | 31 | # Don't set closed-for-staleness label to skip closing very old issues 32 | # regardless of label 33 | closed-for-staleness-label: closed-for-staleness 34 | 35 | # Issue timing 36 | days-before-stale: 10 37 | days-before-close: 4 38 | days-before-ancient: 36500 39 | 40 | # If you don't want to mark a issue as being ancient based on a 41 | # threshold of "upvotes", you can set this here. An "upvote" is 42 | # the total number of +1, heart, hooray, and rocket reactions 43 | # on an issue. 44 | minimum-upvotes-to-exempt: 1 45 | 46 | repo-token: ${{ secrets.GITHUB_TOKEN }} 47 | loglevel: DEBUG 48 | # Set dry-run to true to not perform label or close actions. 49 | dry-run: false 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | aws-iot-device-sdk-java-samples/target/ 4 | aws-iot-device-sdk-java/target/ -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | AWS IoT Device SDK for Java 2 | Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | This product includes software developed by 5 | Amazon Technologies, Inc (http://www.amazon.com/). 6 | 7 | ********************** 8 | THIRD PARTY COMPONENTS 9 | ********************** 10 | This software includes third party software subject to the following copyrights: 11 | - PKCS#1 and PKCS#8 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. 12 | 13 | The licenses for these third party components are included in LICENSE.txt -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.amazonaws 5 | aws-iot-device-sdk-java-pom 6 | 0.0.1-dev 7 | 8 | aws-iot-device-sdk-java-samples 9 | 10 | 11 | com.amazonaws 12 | aws-iot-device-sdk-java 13 | 0.0.1-dev 14 | 15 | 16 | commons-codec 17 | commons-codec 18 | 1.12 19 | 20 | 21 | 22 | 23 | 24 | org.apache.maven.plugins 25 | maven-compiler-plugin 26 | 3.5.1 27 | 28 | 29 | com/amazonaws/services/iot/client/sample/odin/*.java 30 | 31 | 32 | 33 | 34 | org.apache.maven.plugins 35 | maven-source-plugin 36 | 3.0.0 37 | 38 | 39 | attach-sources 40 | 41 | jar-no-fork 42 | 43 | 44 | 45 | 46 | 47 | org.apache.maven.plugins 48 | maven-javadoc-plugin 49 | 2.10.3 50 | 51 | 8 52 | *.odin.* 53 | 54 | 55 | 56 | attach-javadocs 57 | 58 | jar 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/samples-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.amazonaws 4 | aws-iot-device-sdk-java-samples 5 | 0.0.1-dev 6 | 7 | 8 | org.apache.maven.plugins 9 | maven-compiler-plugin 10 | 3.5.1 11 | 12 | 13 | com.amazonaws 14 | aws-iot-device-sdk-java 15 | 0.0.1-dev 16 | 17 | 18 | com.fasterxml.jackson.core 19 | jackson-core 20 | 2.13.4 21 | 22 | 23 | com.fasterxml.jackson.core 24 | jackson-databind 25 | 2.13.4.2 26 | 27 | 28 | 29 | 30 | 31 | org.apache.maven.plugins 32 | maven-compiler-plugin 33 | 34 | 1.7 35 | 1.7 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/java/com/amazonaws/services/iot/client/sample/pubSub/NonBlockingPublishListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.sample.pubSub; 17 | 18 | import com.amazonaws.services.iot.client.AWSIotMessage; 19 | import com.amazonaws.services.iot.client.AWSIotQos; 20 | 21 | /** 22 | * This class extends {@link AWSIotMessage} to provide customized handlers for 23 | * non-blocking message publishing. 24 | */ 25 | public class NonBlockingPublishListener extends AWSIotMessage { 26 | 27 | public NonBlockingPublishListener(String topic, AWSIotQos qos, String payload) { 28 | super(topic, qos, payload); 29 | } 30 | 31 | @Override 32 | public void onSuccess() { 33 | System.out.println(System.currentTimeMillis() + ": >>> " + getStringPayload()); 34 | } 35 | 36 | @Override 37 | public void onFailure() { 38 | System.out.println(System.currentTimeMillis() + ": publish failed for " + getStringPayload()); 39 | } 40 | 41 | @Override 42 | public void onTimeout() { 43 | System.out.println(System.currentTimeMillis() + ": publish timeout for " + getStringPayload()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/java/com/amazonaws/services/iot/client/sample/pubSub/PublishSubscribeSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.sample.pubSub; 17 | 18 | import com.amazonaws.services.iot.client.AWSIotMqttClient; 19 | import com.amazonaws.services.iot.client.AWSIotException; 20 | import com.amazonaws.services.iot.client.AWSIotMessage; 21 | import com.amazonaws.services.iot.client.AWSIotQos; 22 | import com.amazonaws.services.iot.client.AWSIotTimeoutException; 23 | import com.amazonaws.services.iot.client.AWSIotTopic; 24 | import com.amazonaws.services.iot.client.sample.sampleUtil.CommandArguments; 25 | import com.amazonaws.services.iot.client.sample.sampleUtil.SampleUtil; 26 | import com.amazonaws.services.iot.client.sample.sampleUtil.SampleUtil.KeyStorePasswordPair; 27 | 28 | /** 29 | * This is an example that uses {@link AWSIotMqttClient} to subscribe to a topic and 30 | * publish messages to it. Both blocking and non-blocking publishing are 31 | * demonstrated in this example. 32 | */ 33 | public class PublishSubscribeSample { 34 | 35 | private static final String TestTopic = "sdk/test/java"; 36 | private static final AWSIotQos TestTopicQos = AWSIotQos.QOS0; 37 | 38 | private static AWSIotMqttClient awsIotClient; 39 | 40 | public static void setClient(AWSIotMqttClient client) { 41 | awsIotClient = client; 42 | } 43 | 44 | public static class BlockingPublisher implements Runnable { 45 | private final AWSIotMqttClient awsIotClient; 46 | 47 | public BlockingPublisher(AWSIotMqttClient awsIotClient) { 48 | this.awsIotClient = awsIotClient; 49 | } 50 | 51 | @Override 52 | public void run() { 53 | long counter = 1; 54 | 55 | while (true) { 56 | String payload = "hello from blocking publisher - " + (counter++); 57 | try { 58 | awsIotClient.publish(TestTopic, payload); 59 | } catch (AWSIotException e) { 60 | System.out.println(System.currentTimeMillis() + ": publish failed for " + payload); 61 | } 62 | System.out.println(System.currentTimeMillis() + ": >>> " + payload); 63 | 64 | try { 65 | Thread.sleep(1000); 66 | } catch (InterruptedException e) { 67 | System.out.println(System.currentTimeMillis() + ": BlockingPublisher was interrupted"); 68 | return; 69 | } 70 | } 71 | } 72 | } 73 | 74 | public static class NonBlockingPublisher implements Runnable { 75 | private final AWSIotMqttClient awsIotClient; 76 | 77 | public NonBlockingPublisher(AWSIotMqttClient awsIotClient) { 78 | this.awsIotClient = awsIotClient; 79 | } 80 | 81 | @Override 82 | public void run() { 83 | long counter = 1; 84 | 85 | while (true) { 86 | String payload = "hello from non-blocking publisher - " + (counter++); 87 | AWSIotMessage message = new NonBlockingPublishListener(TestTopic, TestTopicQos, payload); 88 | try { 89 | awsIotClient.publish(message); 90 | } catch (AWSIotException e) { 91 | System.out.println(System.currentTimeMillis() + ": publish failed for " + payload); 92 | } 93 | 94 | try { 95 | Thread.sleep(1000); 96 | } catch (InterruptedException e) { 97 | System.out.println(System.currentTimeMillis() + ": NonBlockingPublisher was interrupted"); 98 | return; 99 | } 100 | } 101 | } 102 | } 103 | 104 | private static void initClient(CommandArguments arguments) { 105 | String clientEndpoint = arguments.getNotNull("clientEndpoint", SampleUtil.getConfig("clientEndpoint")); 106 | String clientId = arguments.getNotNull("clientId", SampleUtil.getConfig("clientId")); 107 | 108 | String certificateFile = arguments.get("certificateFile", SampleUtil.getConfig("certificateFile")); 109 | String privateKeyFile = arguments.get("privateKeyFile", SampleUtil.getConfig("privateKeyFile")); 110 | if (awsIotClient == null && certificateFile != null && privateKeyFile != null) { 111 | String algorithm = arguments.get("keyAlgorithm", SampleUtil.getConfig("keyAlgorithm")); 112 | 113 | KeyStorePasswordPair pair = SampleUtil.getKeyStorePasswordPair(certificateFile, privateKeyFile, algorithm); 114 | 115 | awsIotClient = new AWSIotMqttClient(clientEndpoint, clientId, pair.keyStore, pair.keyPassword); 116 | } 117 | 118 | if (awsIotClient == null) { 119 | String awsAccessKeyId = arguments.get("awsAccessKeyId", SampleUtil.getConfig("awsAccessKeyId")); 120 | String awsSecretAccessKey = arguments.get("awsSecretAccessKey", SampleUtil.getConfig("awsSecretAccessKey")); 121 | String sessionToken = arguments.get("sessionToken", SampleUtil.getConfig("sessionToken")); 122 | 123 | if (awsAccessKeyId != null && awsSecretAccessKey != null) { 124 | awsIotClient = new AWSIotMqttClient(clientEndpoint, clientId, awsAccessKeyId, awsSecretAccessKey, 125 | sessionToken); 126 | } 127 | } 128 | 129 | if (awsIotClient == null) { 130 | throw new IllegalArgumentException("Failed to construct client due to missing certificate or credentials."); 131 | } 132 | } 133 | 134 | public static void main(String args[]) throws InterruptedException, AWSIotException, AWSIotTimeoutException { 135 | CommandArguments arguments = CommandArguments.parse(args); 136 | initClient(arguments); 137 | 138 | awsIotClient.connect(); 139 | 140 | AWSIotTopic topic = new TestTopicListener(TestTopic, TestTopicQos); 141 | awsIotClient.subscribe(topic, true); 142 | 143 | Thread blockingPublishThread = new Thread(new BlockingPublisher(awsIotClient)); 144 | Thread nonBlockingPublishThread = new Thread(new NonBlockingPublisher(awsIotClient)); 145 | 146 | blockingPublishThread.start(); 147 | nonBlockingPublishThread.start(); 148 | 149 | blockingPublishThread.join(); 150 | nonBlockingPublishThread.join(); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/java/com/amazonaws/services/iot/client/sample/pubSub/TestTopicListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.sample.pubSub; 17 | 18 | import com.amazonaws.services.iot.client.AWSIotMessage; 19 | import com.amazonaws.services.iot.client.AWSIotQos; 20 | import com.amazonaws.services.iot.client.AWSIotTopic; 21 | 22 | /** 23 | * This class extends {@link AWSIotTopic} to receive messages from a subscribed 24 | * topic. 25 | */ 26 | public class TestTopicListener extends AWSIotTopic { 27 | 28 | public TestTopicListener(String topic, AWSIotQos qos) { 29 | super(topic, qos); 30 | } 31 | 32 | @Override 33 | public void onMessage(AWSIotMessage message) { 34 | System.out.println(System.currentTimeMillis() + ": <<< " + message.getStringPayload()); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/CommandArguments.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.sample.sampleUtil; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | public class CommandArguments { 22 | 23 | private final Map arguments = new HashMap(); 24 | 25 | private CommandArguments(String[] args) { 26 | String name = null; 27 | 28 | for (int i = 0; i < args.length; i++) { 29 | String arg = args[i].trim(); 30 | if (name == null) { 31 | if (arg.startsWith("-")) { 32 | name = arg.replaceFirst("^-+", ""); 33 | if (name.length() < 1) { 34 | name = null; 35 | } 36 | } 37 | continue; 38 | } 39 | 40 | if (arg.startsWith("-")) { 41 | arguments.put(name.toLowerCase(), null); 42 | 43 | name = arg.replaceFirst("^-+", ""); 44 | if (name.length() < 1) { 45 | name = null; 46 | } 47 | } else { 48 | arguments.put(name.toLowerCase(), arg); 49 | name = null; 50 | } 51 | } 52 | 53 | if (name != null) { 54 | arguments.put(name.toLowerCase(), null); 55 | } 56 | } 57 | 58 | public static CommandArguments parse(String[] args) { 59 | return new CommandArguments(args); 60 | } 61 | 62 | public String get(String name) { 63 | return arguments.get(name.toLowerCase()); 64 | } 65 | 66 | public String get(String name, String defaultValue) { 67 | String value = arguments.get(name.toLowerCase()); 68 | if (value == null) { 69 | value = defaultValue; 70 | } 71 | return value; 72 | } 73 | 74 | public String getNotNull(String name) { 75 | String value = get(name); 76 | if (value == null) { 77 | throw new RuntimeException("Missing required argument for " + name); 78 | } 79 | return value; 80 | } 81 | 82 | public String getNotNull(String name, String defaultValue) { 83 | String value = get(name, defaultValue); 84 | if (value == null) { 85 | throw new RuntimeException("Missing required argument for " + name); 86 | } 87 | return value; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/SampleUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.sample.sampleUtil; 17 | 18 | import java.io.BufferedInputStream; 19 | import java.io.DataInputStream; 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.math.BigInteger; 25 | import java.net.URL; 26 | import java.security.GeneralSecurityException; 27 | import java.security.KeyStore; 28 | import java.security.KeyStoreException; 29 | import java.security.NoSuchAlgorithmException; 30 | import java.security.PrivateKey; 31 | import java.security.SecureRandom; 32 | import java.security.cert.Certificate; 33 | import java.security.cert.CertificateException; 34 | import java.security.cert.CertificateFactory; 35 | import java.util.List; 36 | import java.util.Properties; 37 | 38 | /** 39 | * This is a helper class to facilitate reading of the configurations and 40 | * certificate from the resource files. 41 | */ 42 | public class SampleUtil { 43 | private static final String PropertyFile = "aws-iot-sdk-samples.properties"; 44 | 45 | public static class KeyStorePasswordPair { 46 | public KeyStore keyStore; 47 | public String keyPassword; 48 | 49 | public KeyStorePasswordPair(KeyStore keyStore, String keyPassword) { 50 | this.keyStore = keyStore; 51 | this.keyPassword = keyPassword; 52 | } 53 | } 54 | 55 | public static String getConfig(String name) { 56 | Properties prop = new Properties(); 57 | URL resource = SampleUtil.class.getResource(PropertyFile); 58 | if (resource == null) { 59 | return null; 60 | } 61 | try (InputStream stream = resource.openStream()) { 62 | prop.load(stream); 63 | } catch (IOException e) { 64 | return null; 65 | } 66 | String value = prop.getProperty(name); 67 | if (value == null || value.trim().length() == 0) { 68 | return null; 69 | } else { 70 | return value; 71 | } 72 | } 73 | 74 | public static KeyStorePasswordPair getKeyStorePasswordPair(final String certificateFile, final String privateKeyFile) { 75 | return getKeyStorePasswordPair(certificateFile, privateKeyFile, null); 76 | } 77 | 78 | public static KeyStorePasswordPair getKeyStorePasswordPair(final String certificateFile, final String privateKeyFile, 79 | String keyAlgorithm) { 80 | if (certificateFile == null || privateKeyFile == null) { 81 | System.out.println("Certificate or private key file missing"); 82 | return null; 83 | } 84 | System.out.println("Cert file:" +certificateFile + " Private key: "+ privateKeyFile); 85 | 86 | final PrivateKey privateKey = loadPrivateKeyFromFile(privateKeyFile, keyAlgorithm); 87 | 88 | final List certChain = loadCertificatesFromFile(certificateFile); 89 | 90 | if (certChain == null || privateKey == null) return null; 91 | 92 | return getKeyStorePasswordPair(certChain, privateKey); 93 | } 94 | 95 | public static KeyStorePasswordPair getKeyStorePasswordPair(final List certificates, final PrivateKey privateKey) { 96 | KeyStore keyStore; 97 | String keyPassword; 98 | try { 99 | keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 100 | keyStore.load(null); 101 | 102 | // randomly generated key password for the key in the KeyStore 103 | keyPassword = new BigInteger(128, new SecureRandom()).toString(32); 104 | 105 | Certificate[] certChain = new Certificate[certificates.size()]; 106 | certChain = certificates.toArray(certChain); 107 | keyStore.setKeyEntry("alias", privateKey, keyPassword.toCharArray(), certChain); 108 | } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { 109 | System.out.println("Failed to create key store"); 110 | return null; 111 | } 112 | 113 | return new KeyStorePasswordPair(keyStore, keyPassword); 114 | } 115 | 116 | private static List loadCertificatesFromFile(final String filename) { 117 | File file = new File(filename); 118 | if (!file.exists()) { 119 | System.out.println("Certificate file: " + filename + " is not found."); 120 | return null; 121 | } 122 | 123 | try (BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file))) { 124 | final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 125 | return (List) certFactory.generateCertificates(stream); 126 | } catch (IOException | CertificateException e) { 127 | System.out.println("Failed to load certificate file " + filename); 128 | } 129 | return null; 130 | } 131 | 132 | private static PrivateKey loadPrivateKeyFromFile(final String filename, final String algorithm) { 133 | PrivateKey privateKey = null; 134 | 135 | File file = new File(filename); 136 | if (!file.exists()) { 137 | System.out.println("Private key file not found: " + filename); 138 | return null; 139 | } 140 | try (DataInputStream stream = new DataInputStream(new FileInputStream(file))) { 141 | privateKey = PrivateKeyReader.getPrivateKey(stream, algorithm); 142 | } catch (IOException | GeneralSecurityException e) { 143 | System.out.println("Failed to load private key from file " + filename); 144 | } 145 | 146 | return privateKey; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/java/com/amazonaws/services/iot/client/sample/shadow/ConnectedWindow.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.sample.shadow; 17 | 18 | import java.util.Random; 19 | 20 | import com.amazonaws.services.iot.client.AWSIotDevice; 21 | import com.amazonaws.services.iot.client.AWSIotDeviceProperty; 22 | 23 | /** 24 | * This class encapsulates an actual device. It extends {@link AWSIotDevice} to 25 | * define properties that are to be kept in sync with the AWS IoT shadow. 26 | */ 27 | public class ConnectedWindow extends AWSIotDevice { 28 | 29 | public ConnectedWindow(String thingName) { 30 | super(thingName); 31 | } 32 | 33 | @AWSIotDeviceProperty 34 | private boolean windowOpen; 35 | 36 | @AWSIotDeviceProperty 37 | private float roomTemperature; 38 | 39 | public boolean getWindowOpen() { 40 | // 1. read the window state from the window actuator 41 | boolean reportedState = this.windowOpen; 42 | System.out.println( 43 | System.currentTimeMillis() + " >>> reported window state: " + (reportedState ? "open" : "closed")); 44 | 45 | // 2. return the current window state 46 | return reportedState; 47 | } 48 | 49 | public void setWindowOpen(boolean desiredState) { 50 | // 1. update the window actuator with the desired state 51 | this.windowOpen = desiredState; 52 | 53 | System.out.println( 54 | System.currentTimeMillis() + " <<< desired window state to " + (desiredState ? "open" : "closed")); 55 | } 56 | 57 | public float getRoomTemperature() { 58 | // 1. Read the actual room temperature from the thermostat 59 | Random rand = new Random(); 60 | float minTemperature = 20.0f; 61 | float maxTemperature = 85.0f; 62 | float reportedTemperature = rand.nextFloat() * (maxTemperature - minTemperature) + minTemperature; 63 | 64 | // 2. (optionally) update the local copy 65 | this.roomTemperature = reportedTemperature; 66 | 67 | // 3. return the current room temperature 68 | System.out.println(System.currentTimeMillis() + " >>> reported room temperature: " + reportedTemperature); 69 | return this.roomTemperature; 70 | } 71 | 72 | public void setRoomTemperature(float desiredTemperature) { 73 | // no-op as room temperature is a read-only property. It's not required 74 | // to have this setter. 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/java/com/amazonaws/services/iot/client/sample/shadow/ShadowSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.sample.shadow; 17 | 18 | import com.amazonaws.services.iot.client.AWSIotConnectionStatus; 19 | import com.amazonaws.services.iot.client.AWSIotDevice; 20 | import com.amazonaws.services.iot.client.AWSIotException; 21 | import com.amazonaws.services.iot.client.AWSIotMessage; 22 | import com.amazonaws.services.iot.client.AWSIotMqttClient; 23 | import com.amazonaws.services.iot.client.AWSIotQos; 24 | import com.amazonaws.services.iot.client.sample.sampleUtil.CommandArguments; 25 | import com.amazonaws.services.iot.client.sample.sampleUtil.SampleUtil; 26 | import com.amazonaws.services.iot.client.sample.sampleUtil.SampleUtil.KeyStorePasswordPair; 27 | 28 | /** 29 | * This example demonstrates how to use {@link AWSIotMqttClient} and a derived 30 | * {@link AWSIotDevice} to keep the device connected with its shadow in the 31 | * cloud. This is the recommended way of accessing a shadow and keeping it 32 | * synchronized with the device. The only thing the application needs to provide 33 | * in the derived class is the annotated device properties and their 34 | * corresponding getter and setter methods. 35 | */ 36 | public class ShadowSample { 37 | 38 | private static AWSIotMqttClient awsIotClient; 39 | 40 | public static void setClient(AWSIotMqttClient client) { 41 | awsIotClient = client; 42 | } 43 | 44 | private static void initClient(CommandArguments arguments) { 45 | String clientEndpoint = arguments.getNotNull("clientEndpoint", SampleUtil.getConfig("clientEndpoint")); 46 | String clientId = arguments.getNotNull("clientId", SampleUtil.getConfig("clientId")); 47 | 48 | String certificateFile = arguments.get("certificateFile", SampleUtil.getConfig("certificateFile")); 49 | String privateKeyFile = arguments.get("privateKeyFile", SampleUtil.getConfig("privateKeyFile")); 50 | if (awsIotClient == null && certificateFile != null && privateKeyFile != null) { 51 | String algorithm = arguments.get("keyAlgorithm", SampleUtil.getConfig("keyAlgorithm")); 52 | KeyStorePasswordPair pair = SampleUtil.getKeyStorePasswordPair(certificateFile, privateKeyFile, algorithm); 53 | 54 | awsIotClient = new AWSIotMqttClient(clientEndpoint, clientId, pair.keyStore, pair.keyPassword); 55 | } 56 | 57 | if (awsIotClient == null) { 58 | String awsAccessKeyId = arguments.get("awsAccessKeyId", SampleUtil.getConfig("awsAccessKeyId")); 59 | String awsSecretAccessKey = arguments.get("awsSecretAccessKey", SampleUtil.getConfig("awsSecretAccessKey")); 60 | String sessionToken = arguments.get("sessionToken", SampleUtil.getConfig("sessionToken")); 61 | 62 | if (awsAccessKeyId != null && awsSecretAccessKey != null) { 63 | awsIotClient = new AWSIotMqttClient(clientEndpoint, clientId, awsAccessKeyId, awsSecretAccessKey, 64 | sessionToken); 65 | } 66 | } 67 | 68 | if (awsIotClient == null) { 69 | throw new IllegalArgumentException("Failed to construct client due to missing certificate or credentials."); 70 | } 71 | } 72 | 73 | public static void main(String args[]) throws InterruptedException, AWSIotException { 74 | CommandArguments arguments = CommandArguments.parse(args); 75 | initClient(arguments); 76 | 77 | awsIotClient.setWillMessage(new AWSIotMessage("client/disconnect", AWSIotQos.QOS0, awsIotClient.getClientId())); 78 | 79 | String thingName = arguments.getNotNull("thingName", SampleUtil.getConfig("thingName")); 80 | ConnectedWindow connectedWindow = new ConnectedWindow(thingName); 81 | 82 | awsIotClient.attach(connectedWindow); 83 | awsIotClient.connect(); 84 | 85 | // Delete existing document if any 86 | connectedWindow.delete(); 87 | 88 | AWSIotConnectionStatus status = AWSIotConnectionStatus.DISCONNECTED; 89 | while (true) { 90 | AWSIotConnectionStatus newStatus = awsIotClient.getConnectionStatus(); 91 | if (!status.equals(newStatus)) { 92 | System.out.println(System.currentTimeMillis() + " Connection status changed to " + newStatus); 93 | status = newStatus; 94 | } 95 | 96 | Thread.sleep(1000); 97 | } 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/java/com/amazonaws/services/iot/client/sample/shadowEcho/ShadowEchoSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.sample.shadowEcho; 17 | 18 | import java.io.IOException; 19 | 20 | import com.amazonaws.services.iot.client.AWSIotMqttClient; 21 | import com.amazonaws.services.iot.client.AWSIotDevice; 22 | import com.amazonaws.services.iot.client.AWSIotException; 23 | import com.amazonaws.services.iot.client.AWSIotTimeoutException; 24 | import com.amazonaws.services.iot.client.sample.sampleUtil.CommandArguments; 25 | import com.amazonaws.services.iot.client.sample.sampleUtil.SampleUtil; 26 | import com.amazonaws.services.iot.client.sample.sampleUtil.SampleUtil.KeyStorePasswordPair; 27 | import com.fasterxml.jackson.databind.DeserializationFeature; 28 | import com.fasterxml.jackson.databind.ObjectMapper; 29 | 30 | /** 31 | * This example demonstrates how to use {@link AWSIotDevice} to directly access 32 | * the shadow document. 33 | */ 34 | public class ShadowEchoSample { 35 | 36 | private static AWSIotMqttClient awsIotClient; 37 | 38 | public static void setClient(AWSIotMqttClient client) { 39 | awsIotClient = client; 40 | } 41 | 42 | private static void initClient(CommandArguments arguments) { 43 | String clientEndpoint = arguments.getNotNull("clientEndpoint", SampleUtil.getConfig("clientEndpoint")); 44 | String clientId = arguments.getNotNull("clientId", SampleUtil.getConfig("clientId")); 45 | 46 | String certificateFile = arguments.get("certificateFile", SampleUtil.getConfig("certificateFile")); 47 | String privateKeyFile = arguments.get("privateKeyFile", SampleUtil.getConfig("privateKeyFile")); 48 | if (awsIotClient == null && certificateFile != null && privateKeyFile != null) { 49 | String algorithm = arguments.get("keyAlgorithm", SampleUtil.getConfig("keyAlgorithm")); 50 | KeyStorePasswordPair pair = SampleUtil.getKeyStorePasswordPair(certificateFile, privateKeyFile, algorithm); 51 | 52 | awsIotClient = new AWSIotMqttClient(clientEndpoint, clientId, pair.keyStore, pair.keyPassword); 53 | } 54 | 55 | if (awsIotClient == null) { 56 | String awsAccessKeyId = arguments.get("awsAccessKeyId", SampleUtil.getConfig("awsAccessKeyId")); 57 | String awsSecretAccessKey = arguments.get("awsSecretAccessKey", SampleUtil.getConfig("awsSecretAccessKey")); 58 | String sessionToken = arguments.get("sessionToken", SampleUtil.getConfig("sessionToken")); 59 | 60 | if (awsAccessKeyId != null && awsSecretAccessKey != null) { 61 | awsIotClient = new AWSIotMqttClient(clientEndpoint, clientId, awsAccessKeyId, awsSecretAccessKey, 62 | sessionToken); 63 | } 64 | } 65 | 66 | if (awsIotClient == null) { 67 | throw new IllegalArgumentException("Failed to construct client due to missing certificate or credentials."); 68 | } 69 | } 70 | 71 | public static void main(String args[]) throws IOException, AWSIotException, AWSIotTimeoutException, 72 | InterruptedException { 73 | CommandArguments arguments = CommandArguments.parse(args); 74 | initClient(arguments); 75 | 76 | String thingName = arguments.getNotNull("thingName", SampleUtil.getConfig("thingName")); 77 | AWSIotDevice device = new AWSIotDevice(thingName); 78 | 79 | awsIotClient.attach(device); 80 | awsIotClient.connect(); 81 | 82 | // Delete existing document if any 83 | device.delete(); 84 | 85 | ObjectMapper objectMapper = new ObjectMapper(); 86 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 87 | 88 | Thing thing = new Thing(); 89 | 90 | while (true) { 91 | long desired = thing.state.desired.counter; 92 | thing.state.reported.counter = desired; 93 | thing.state.desired.counter = desired + 1; 94 | 95 | String jsonState = objectMapper.writeValueAsString(thing); 96 | 97 | try { 98 | // Send updated document to the shadow 99 | device.update(jsonState); 100 | System.out.println(System.currentTimeMillis() + ": >>> " + jsonState); 101 | } catch (AWSIotException e) { 102 | System.out.println(System.currentTimeMillis() + ": update failed for " + jsonState); 103 | continue; 104 | } 105 | 106 | try { 107 | // Retrieve updated document from the shadow 108 | String shadowState = device.get(); 109 | System.out.println(System.currentTimeMillis() + ": <<< " + shadowState); 110 | 111 | thing = objectMapper.readValue(shadowState, Thing.class); 112 | } catch (AWSIotException e) { 113 | System.out.println(System.currentTimeMillis() + ": get failed for " + jsonState); 114 | continue; 115 | } 116 | 117 | Thread.sleep(1000); 118 | } 119 | 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/java/com/amazonaws/services/iot/client/sample/shadowEcho/Thing.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.sample.shadowEcho; 17 | 18 | /** 19 | * This POJO class defines a simple document for communicating with the AWS IoT 20 | * thing. It only contains one property ({@code counter}). 21 | */ 22 | public class Thing { 23 | 24 | public State state = new State(); 25 | 26 | public static class State { 27 | public Document reported = new Document(); 28 | public Document desired = new Document(); 29 | } 30 | 31 | public static class Document { 32 | public long counter = 1; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java-samples/src/main/resources/com/amazonaws/services/iot/client/sample/sampleUtil/aws-iot-sdk-samples.properties: -------------------------------------------------------------------------------- 1 | # Client endpoint, e.g. .iot.us-east-1.amazonaws.com 2 | clientEndpoint= 3 | 4 | # Client ID, unique client ID per connection 5 | clientId= 6 | 7 | # Client certificate file 8 | certificateFile= 9 | 10 | # Client private key file 11 | privateKeyFile= 12 | 13 | # Thing name 14 | thingName= -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.amazonaws 5 | aws-iot-device-sdk-java-pom 6 | 0.0.1-dev 7 | 8 | aws-iot-device-sdk-java 9 | 10 | 11 | org.mockito 12 | mockito-core 13 | 2.25.0 14 | test 15 | 16 | 17 | junit 18 | junit 19 | 4.13.1 20 | test 21 | 22 | 23 | org.projectlombok 24 | lombok 25 | 1.18.24 26 | provided 27 | 28 | 29 | com.fasterxml.jackson.core 30 | jackson-core 31 | 2.13.4 32 | 33 | 34 | com.fasterxml.jackson.core 35 | jackson-databind 36 | 2.13.4.2 37 | 38 | 39 | org.eclipse.paho 40 | org.eclipse.paho.client.mqttv3 41 | [1.2.4] 42 | 43 | 44 | com.amazonaws 45 | aws-java-sdk-secretsmanager 46 | 1.12.315 47 | 48 | 49 | 50 | target/generated-sources/delombok 51 | 52 | 53 | org.apache.maven.plugins 54 | maven-compiler-plugin 55 | 3.5.1 56 | 57 | 58 | org.projectlombok 59 | lombok-maven-plugin 60 | 1.18.20.0 61 | 62 | 63 | generate-sources 64 | 65 | delombok 66 | 67 | 68 | false 69 | src/main/java 70 | 71 | 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-source-plugin 77 | 3.0.0 78 | 79 | 80 | attach-sources 81 | 82 | jar-no-fork 83 | 84 | 85 | 86 | 87 | 88 | org.apache.maven.plugins 89 | maven-javadoc-plugin 90 | 2.10.3 91 | 92 | 8 93 | target/generated-sources/delombok 94 | 95 | 96 | 97 | attach-javadocs 98 | 99 | jar 100 | 101 | 102 | 103 | 104 | 105 | maven-surefire-plugin 106 | 2.22.2 107 | 108 | 109 | main-run 110 | 111 | test 112 | 113 | 114 | src/test/java/com/amazonaws/services/iot/client/system_props_mutualAuth.properties 115 | 116 | 117 | 118 | default-test 119 | 120 | test 121 | 122 | 123 | src/test/java/com/amazonaws/services/iot/client/system_props_websocket.properties 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | org.codehaus.mojo 134 | findbugs-maven-plugin 135 | 3.0.5 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/AWSIotConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client; 17 | 18 | /** 19 | * The class provides default values for the library. All the values defined 20 | * here can be overridden at runtime through setter functions in 21 | * {@link AWSIotMqttClient} and {@link AWSIotDevice}. 22 | */ 23 | public class AWSIotConfig { 24 | 25 | /** 26 | * The default value for number of client threads. See also 27 | * {@link AWSIotMqttClient#getNumOfClientThreads()}. 28 | */ 29 | public static final int NUM_OF_CLIENT_THREADS = 1; 30 | 31 | /** 32 | * The default value for client connection timeout (milliseconds). See also 33 | * {@link AWSIotMqttClient#getConnectionTimeout()}. 34 | */ 35 | public static final int CONNECTION_TIMEOUT = 30000; 36 | 37 | /** 38 | * The default value for service acknowledge timeout (milliseconds). See 39 | * also {@link AWSIotMqttClient#getServerAckTimeout()}. 40 | */ 41 | public static final int SERVER_ACK_TIMEOUT = 3000; 42 | 43 | /** 44 | * The default value for client keep-alive interval (milliseconds). See also 45 | * {@link AWSIotMqttClient#getKeepAliveInterval()}. 46 | */ 47 | public static final int KEEP_ALIVE_INTERVAL = 600000; 48 | 49 | /** 50 | * The default value for maximum connection retry times. See also 51 | * {@link AWSIotMqttClient#getMaxConnectionRetries()}. 52 | */ 53 | public static final int MAX_CONNECTION_RETRIES = 5; 54 | 55 | /** 56 | * The default value for connection base retry delay (milliseconds). See 57 | * also {@link AWSIotMqttClient#getBaseRetryDelay()}. 58 | */ 59 | public static final int CONNECTION_BASE_RETRY_DELAY = 3000; 60 | 61 | /** 62 | * The default value for connection maximum retry delay (milliseconds). See 63 | * also {@link AWSIotMqttClient#getMaxRetryDelay()}. 64 | */ 65 | public static final int CONNECTION_MAX_RETRY_DELAY = 30000; 66 | 67 | /** 68 | * The default value for clean session connections. 69 | * See also {@link AWSIotMqttClient#isCleanSession()}. 70 | */ 71 | public static final boolean CLEAN_SESSION = true; 72 | 73 | /** 74 | * The default value for maximum offline queue size. See also 75 | * {@link AWSIotMqttClient#getMaxOfflineQueueSize()}. 76 | */ 77 | public static final int MAX_OFFLINE_QUEUE_SIZE = 64; 78 | 79 | /** 80 | * The default value for device reporting interval (milliseconds). See also 81 | * {@link AWSIotDevice#getReportInterval()}. 82 | */ 83 | public static final int DEVICE_REPORT_INTERVAL = 3000; 84 | 85 | /** 86 | * The default value for enabling device update versioning. See also 87 | * {@link AWSIotDevice#isEnableVersioning()}. 88 | */ 89 | public static final boolean DEVICE_ENABLE_VERSIONING = false; 90 | 91 | /** 92 | * The default value for device reporting QoS level. See also 93 | * {@link AWSIotDevice#getDeviceReportQos()}. 94 | */ 95 | public static final int DEVICE_REPORT_QOS = 0; 96 | 97 | /** 98 | * The default value for the QoS level for subscribing to shadow updates. 99 | * See also {@link AWSIotDevice#getShadowUpdateQos()}. 100 | */ 101 | public static final int DEVICE_SHADOW_UPDATE_QOS = 0; 102 | 103 | /** 104 | * The default value for the QoS level for publishing shadow methods. See 105 | * also {@link AWSIotDevice#getMethodQos()}. 106 | */ 107 | public static final int DEVICE_METHOD_QOS = 0; 108 | 109 | /** 110 | * The default value for the QoS level for subscribing to shadow method 111 | * acknowledgement. See also {@link AWSIotDevice#getMethodAckQos()}. 112 | */ 113 | public static final int DEVICE_METHOD_ACK_QOS = 0; 114 | 115 | } 116 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/AWSIotConnectionStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client; 17 | 18 | /** 19 | * Connection status that can be retrieved through 20 | * {@link AWSIotMqttClient#getConnectionStatus()}. 21 | */ 22 | public enum AWSIotConnectionStatus { 23 | 24 | /** Client successfully connected. */ 25 | CONNECTED, 26 | 27 | /** Not connected. */ 28 | DISCONNECTED, 29 | 30 | /** Automatically reconnecting after connection loss. */ 31 | RECONNECTING 32 | 33 | } 34 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/AWSIotDeviceErrorCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client; 17 | 18 | /** 19 | * These error codes are used by the server in acknowledgement message for the 20 | * shadow methods, namely Get, Update, and Delete. 21 | */ 22 | public enum AWSIotDeviceErrorCode { 23 | 24 | /** The bad request. */ 25 | BAD_REQUEST(400), 26 | /** The Unauthorized. */ 27 | UNAUTHORIZED(401), 28 | /** The Forbidden. */ 29 | FORBIDDEN(403), 30 | /** The Not found. */ 31 | NOT_FOUND(404), 32 | /** The Conflict. */ 33 | CONFLICT(409), 34 | /** The Payload too large. */ 35 | PAYLOAD_TOO_LARGE(413), 36 | /** The Unsupported media type. */ 37 | UNSUPPORTED_MEDIA_TYPE(415), 38 | /** The Too many requests. */ 39 | TOO_MANY_REQUESTS(429), 40 | /** The Internal service failure. */ 41 | INTERNAL_SERVICE_FAILURE(429); 42 | 43 | /** The error code. */ 44 | private final long errorCode; 45 | 46 | /** 47 | * Instantiates a new device error code object. 48 | * 49 | * @param errorCode 50 | * the error code 51 | */ 52 | private AWSIotDeviceErrorCode(final long errorCode) { 53 | this.errorCode = errorCode; 54 | } 55 | 56 | /** 57 | * Gets the error code value. 58 | * 59 | * @return the error code value 60 | */ 61 | public long getValue() { 62 | return this.errorCode; 63 | } 64 | 65 | /** 66 | * Returns the Enum representation of the error code value 67 | * 68 | * @param code 69 | * the error code value 70 | * @return the Enum representation of the error code, or null if the error 71 | * code is unknown 72 | */ 73 | public static AWSIotDeviceErrorCode valueOf(long code) { 74 | for (AWSIotDeviceErrorCode errorCode : AWSIotDeviceErrorCode.values()) { 75 | if (errorCode.errorCode == code) { 76 | return errorCode; 77 | } 78 | } 79 | 80 | return null; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/AWSIotDeviceProperty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client; 17 | 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | 21 | /** 22 | * Annotation class that is used to annotate properties in {@link AWSIotDevice}. 23 | * Properties annotated must be accessible via corresponding getter and setter 24 | * methods. 25 | *

26 | * With optional values provided by this annotation class, properties can also 27 | * be configured to disable reporting to the shadow or not to accept updates 28 | * from the shadow. If {@link #enableReport()} is disabled, property getter 29 | * function is not required. Likewise, if {@link #allowUpdate()} is disabled for 30 | * a property, its setter method is not required. 31 | *

32 | */ 33 | @Retention(RetentionPolicy.RUNTIME) 34 | public @interface AWSIotDeviceProperty { 35 | 36 | /** 37 | * An optional name can be provided to the annotated property, which will be 38 | * used for publishing to the shadow as well as receiving updates from the 39 | * shadow. If not provided, the actual property name will be used. 40 | * 41 | * @return the name of the property. 42 | */ 43 | String name() default ""; 44 | 45 | /** 46 | * Enable reporting the annotated property to the shadow. It's enabled by 47 | * default. 48 | * 49 | * @return true to enable reporting to the shadow, false otherwise. 50 | */ 51 | boolean enableReport() default true; 52 | 53 | /** 54 | * Allow updates from the shadow. It's enabled by default. 55 | * 56 | * @return true to allow updates from the shadow, false otherwise. 57 | */ 58 | boolean allowUpdate() default true; 59 | 60 | } 61 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/AWSIotException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client; 17 | 18 | import lombok.Getter; 19 | import lombok.Setter; 20 | 21 | /** 22 | * This is a generic exception that can be thrown in most of the APIs, blocking 23 | * and non-blocking, by the library. 24 | */ 25 | public class AWSIotException extends Exception { 26 | 27 | /** The Constant serialVersionUID. */ 28 | private static final long serialVersionUID = 1L; 29 | 30 | /** 31 | * Error code for shadow methods. It's only applicable to exceptions thrown 32 | * by those shadow method APIs. 33 | * 34 | * @param errorCode the new error code for the shadow method exception 35 | * @return the error code of the shadow method exception 36 | */ 37 | @Getter 38 | @Setter 39 | private AWSIotDeviceErrorCode errorCode; 40 | 41 | /** 42 | * Instantiates a new exception object. 43 | * 44 | * @param message 45 | * the error message 46 | */ 47 | public AWSIotException(String message) { 48 | super(message); 49 | } 50 | 51 | /** 52 | * Instantiates a new exception object. 53 | * 54 | * @param errorCode 55 | * the error code 56 | * @param message 57 | * the error message 58 | */ 59 | public AWSIotException(AWSIotDeviceErrorCode errorCode, String message) { 60 | super(message); 61 | this.errorCode = errorCode; 62 | } 63 | 64 | /** 65 | * Instantiates a new exception object. 66 | * 67 | * @param cause 68 | * the cause. A null value is permitted, and indicates that the 69 | * cause is nonexistent or unknown. 70 | */ 71 | public AWSIotException(Throwable cause) { 72 | super(cause); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/AWSIotMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client; 17 | 18 | import java.io.UnsupportedEncodingException; 19 | 20 | import com.amazonaws.services.iot.client.core.AwsIotMessageCallback; 21 | import com.amazonaws.services.iot.client.core.AwsIotRuntimeException; 22 | 23 | import lombok.Getter; 24 | import lombok.Setter; 25 | 26 | /** 27 | * A common data structure that is used in a lot of non-blocking APIs in this 28 | * library. 29 | *

30 | * It provides common data elements, such as {@link #topic}, {@link #qos}, and 31 | * {@link #payload}, used by the APIs. 32 | *

33 | *

34 | * It also contains callback functions that can be overridden to provide 35 | * customized handlers. The callback functions are invoked when a non-blocking 36 | * API call has completed successfully, unsuccessfully, or timed out. 37 | * Applications wish to have customized callback functions must extend this 38 | * class or its child classes, such as {@link AWSIotTopic}. 39 | */ 40 | public class AWSIotMessage implements AwsIotMessageCallback { 41 | 42 | /** 43 | * The topic the message is received from or published to. 44 | * 45 | * @param topic the new topic of the message 46 | * @return the current topic of the message 47 | */ 48 | @Getter 49 | @Setter 50 | protected String topic; 51 | 52 | /** 53 | * The MQTT QoS level for the message. 54 | * 55 | * @param qos the new QoS level 56 | * @return the current QoS level 57 | */ 58 | @Getter 59 | @Setter 60 | protected AWSIotQos qos; 61 | 62 | /** 63 | * The payload of the message. 64 | */ 65 | protected byte[] payload; 66 | 67 | /** 68 | * Error code for shadow methods. It's only applicable to messages returned 69 | * by those shadow method APIs. 70 | * 71 | * @param errorCode the new error code for the shadow method 72 | * @return the current error code of the shadow method 73 | */ 74 | @Getter 75 | @Setter 76 | protected AWSIotDeviceErrorCode errorCode; 77 | 78 | /** 79 | * Error message for shadow methods. It's only applicable to messages 80 | * returned by those shadow method APIs. 81 | * 82 | * @param errorMessage the new error message for the shadow method 83 | * @return the current error message of the shadow method 84 | */ 85 | @Getter 86 | @Setter 87 | protected String errorMessage; 88 | 89 | /** 90 | * Instantiates a new message object. 91 | * 92 | * @param topic 93 | * the topic of the message 94 | * @param qos 95 | * the QoS level of the message 96 | */ 97 | public AWSIotMessage(String topic, AWSIotQos qos) { 98 | this.topic = topic; 99 | this.qos = qos; 100 | } 101 | 102 | /** 103 | * Instantiates a new message object. 104 | * 105 | * @param topic 106 | * the topic of the message 107 | * @param qos 108 | * the QoS level of the message 109 | * @param payload 110 | * the payload of the message 111 | */ 112 | public AWSIotMessage(String topic, AWSIotQos qos, byte[] payload) { 113 | this.topic = topic; 114 | this.qos = qos; 115 | setPayload(payload); 116 | } 117 | 118 | /** 119 | * Instantiates a new message object. 120 | * 121 | * @param topic 122 | * the topic of the message 123 | * @param qos 124 | * the QoS level of the message 125 | * @param payload 126 | * the payload of the message 127 | */ 128 | public AWSIotMessage(String topic, AWSIotQos qos, String payload) { 129 | this.topic = topic; 130 | this.qos = qos; 131 | setStringPayload(payload); 132 | } 133 | 134 | /** 135 | * Gets the byte array payload. 136 | * 137 | * @return the byte array payload 138 | */ 139 | public byte[] getPayload() { 140 | if (payload == null) { 141 | return null; 142 | } 143 | 144 | return payload.clone(); 145 | } 146 | 147 | /** 148 | * Sets the byte array payload. 149 | * 150 | * @param payload 151 | * the new byte array payload 152 | */ 153 | public void setPayload(byte[] payload) { 154 | if (payload == null) { 155 | this.payload = null; 156 | return; 157 | } 158 | 159 | this.payload = payload.clone(); 160 | } 161 | 162 | /** 163 | * Gets the string payload. 164 | * 165 | * @return the string payload 166 | */ 167 | public String getStringPayload() { 168 | if (payload == null) { 169 | return null; 170 | } 171 | 172 | String str; 173 | try { 174 | str = new String(payload, "UTF-8"); 175 | } catch (UnsupportedEncodingException e) { 176 | throw new AwsIotRuntimeException(e); 177 | } 178 | return str; 179 | } 180 | 181 | /** 182 | * Sets the string payload. 183 | * 184 | * @param payload 185 | * the new string payload 186 | */ 187 | public void setStringPayload(String payload) { 188 | if (payload == null) { 189 | this.payload = null; 190 | return; 191 | } 192 | 193 | try { 194 | this.payload = payload.getBytes("UTF-8"); 195 | } catch (UnsupportedEncodingException e) { 196 | throw new AwsIotRuntimeException(e); 197 | } 198 | } 199 | 200 | /** 201 | * Callback function to be invoked a non-block API has completed 202 | * successfully. 203 | */ 204 | @Override 205 | public void onSuccess() { 206 | // Default callback implementation is no-op 207 | } 208 | 209 | /** 210 | * Callback function to be invoked a non-block API has completed 211 | * unsuccessfully. 212 | */ 213 | @Override 214 | public void onFailure() { 215 | // Default callback implementation is no-op 216 | } 217 | 218 | /** 219 | * Callback function to be invoked a non-block API has timed out. 220 | */ 221 | @Override 222 | public void onTimeout() { 223 | // Default callback implementation is no-op 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/AWSIotQos.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client; 17 | 18 | /** 19 | * QoS definitions. The AWS IoT service supports QoS0 and QoS1 defined by the 20 | * MQTT protocol. 21 | */ 22 | public enum AWSIotQos { 23 | 24 | /** The QoS0. */ 25 | QOS0(0), 26 | 27 | /** The QoS1. */ 28 | QOS1(1); 29 | 30 | /** The qos. */ 31 | private final int qos; 32 | 33 | /** 34 | * Instantiates a QoS object. 35 | * 36 | * @param qos 37 | * the QoS level 38 | */ 39 | private AWSIotQos(final int qos) { 40 | this.qos = qos; 41 | } 42 | 43 | /** 44 | * Gets the integer representation of the QoS 45 | * 46 | * @return the integer value of the QoS 47 | */ 48 | public int getValue() { 49 | return this.qos; 50 | } 51 | 52 | /** 53 | * Gets the Enum representation of the QoS 54 | * 55 | * @param qos 56 | * the integer value of the QoS 57 | * @return the Enum value of the QoS 58 | */ 59 | public static AWSIotQos valueOf(int qos) { 60 | if (qos == 0) { 61 | return QOS0; 62 | } else if (qos == 1) { 63 | return QOS1; 64 | } else { 65 | throw new IllegalArgumentException("QoS not supported"); 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/AWSIotTimeoutException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client; 17 | 18 | /** 19 | * This timeout exception can be thrown by the blocking APIs in this library 20 | * when expected time has elapsed. 21 | */ 22 | public class AWSIotTimeoutException extends Exception { 23 | 24 | /** The Constant serialVersionUID. */ 25 | private static final long serialVersionUID = 1L; 26 | 27 | /** 28 | * Instantiates a new exception object. 29 | * 30 | * @param message 31 | * the error message 32 | */ 33 | public AWSIotTimeoutException(String message) { 34 | super(message); 35 | } 36 | 37 | /** 38 | * Instantiates a new exception object. 39 | * 40 | * @param cause 41 | * the cause. A null value is permitted, and indicates that the 42 | * cause is nonexistent or unknown. 43 | */ 44 | public AWSIotTimeoutException(Throwable cause) { 45 | super(cause); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/AWSIotTopic.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client; 17 | 18 | import com.amazonaws.services.iot.client.core.AwsIotTopicCallback; 19 | 20 | /** 21 | * This class is used for subscribing to a topic in the subscription APIs, such 22 | * as {@link AWSIotMqttClient#subscribe(AWSIotTopic topic)}. 23 | *

24 | * In contains a callback function, {@link #onMessage}, that is invoked when a 25 | * subscribed message has arrived. In most cases, applications are expected to 26 | * override the default {@link #onMessage} method in order to access the message 27 | * payload. 28 | *

29 | *

30 | * This class extends {@link AWSIotMessage}, therefore callback functions in 31 | * {@link AWSIotMessage} can also be overridden if the application wishes to be 32 | * invoked for the outcomes of the subscription API. For more details, please 33 | * refer to {@link AWSIotMessage}. 34 | *

35 | */ 36 | public class AWSIotTopic extends AWSIotMessage implements AwsIotTopicCallback { 37 | 38 | /** 39 | * Instantiates a new topic object. 40 | * 41 | * @param topic 42 | * the topic to be subscribed to 43 | */ 44 | public AWSIotTopic(String topic) { 45 | super(topic, AWSIotQos.QOS0); 46 | } 47 | 48 | /** 49 | * Instantiates a new topic object. 50 | * 51 | * @param topic 52 | * the topic to be subscribed to 53 | * @param qos 54 | * the MQTT QoS level for the subscription 55 | */ 56 | public AWSIotTopic(String topic, AWSIotQos qos) { 57 | super(topic, qos); 58 | } 59 | 60 | /** 61 | * Callback function to be invoked upon the arrival of a subscribed message. 62 | * 63 | * @param message 64 | * the message received 65 | */ 66 | @Override 67 | public void onMessage(AWSIotMessage message) { 68 | // Default callback implementation is no-op 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/auth/Credentials.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0. 4 | */ 5 | 6 | package com.amazonaws.services.iot.client.auth; 7 | 8 | /** 9 | * A class representing a set of AWS credentials. 10 | */ 11 | public class Credentials { 12 | 13 | private String accessKeyId; 14 | private String secretAccessKey; 15 | private String sessionToken; 16 | 17 | public Credentials(String accessKeyId, String secretAccessKey) { 18 | this(accessKeyId, secretAccessKey, null); 19 | } 20 | 21 | public Credentials(String accessKeyId, String secretAccessKey, String sessionToken) { 22 | this.accessKeyId = accessKeyId.trim(); 23 | this.secretAccessKey = secretAccessKey; 24 | this.sessionToken = sessionToken; 25 | } 26 | 27 | public String getAccessKeyId() { return accessKeyId; } 28 | public String getSecretAccessKey() { return secretAccessKey; } 29 | public String getSessionToken() { return sessionToken; } 30 | } 31 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/auth/CredentialsProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0. 4 | */ 5 | 6 | package com.amazonaws.services.iot.client.auth; 7 | 8 | public interface CredentialsProvider { 9 | 10 | Credentials getCredentials(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/auth/StaticCredentialsProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0. 4 | */ 5 | 6 | package com.amazonaws.services.iot.client.auth; 7 | 8 | public class StaticCredentialsProvider implements CredentialsProvider { 9 | 10 | private Credentials credentials; 11 | 12 | public StaticCredentialsProvider(Credentials credentials) { 13 | this.credentials = credentials; 14 | } 15 | 16 | public Credentials getCredentials() { 17 | return credentials; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/core/AwsIotConnectionCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.core; 17 | 18 | /** 19 | * This interface class defines functions called under different connection 20 | * events. 21 | */ 22 | public interface AwsIotConnectionCallback { 23 | 24 | /** 25 | * On connection success. 26 | */ 27 | void onConnectionSuccess(); 28 | 29 | /** 30 | * On connection failure. 31 | */ 32 | void onConnectionFailure(); 33 | 34 | /** 35 | * On connection closed. 36 | */ 37 | void onConnectionClosed(); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/core/AwsIotConnectionType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.core; 17 | 18 | /** 19 | * Connection types supported by this library. 20 | */ 21 | public enum AwsIotConnectionType { 22 | 23 | /** The mqtt over tls. */ 24 | MQTT_OVER_TLS, 25 | 26 | /** The mqtt over websocket. */ 27 | MQTT_OVER_WEBSOCKET 28 | 29 | } 30 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/core/AwsIotMessageCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.core; 17 | 18 | /** 19 | * This interface class defines functions called under different message related 20 | * events. 21 | */ 22 | public interface AwsIotMessageCallback { 23 | 24 | /** 25 | * On success. 26 | */ 27 | void onSuccess(); 28 | 29 | /** 30 | * On failure. 31 | */ 32 | void onFailure(); 33 | 34 | /** 35 | * On timeout. 36 | */ 37 | void onTimeout(); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/core/AwsIotRetryableException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.core; 17 | 18 | /** 19 | * This exception class is used internally in the library to track retryable 20 | * events. 21 | */ 22 | public class AwsIotRetryableException extends Exception { 23 | 24 | private static final long serialVersionUID = 1L; 25 | 26 | public AwsIotRetryableException(String message) { 27 | super(message); 28 | } 29 | 30 | public AwsIotRetryableException(Throwable e) { 31 | super(e); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/core/AwsIotRuntimeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.core; 17 | 18 | /** 19 | * This exception class is used internally in the library for runtime errors. 20 | */ 21 | public class AwsIotRuntimeException extends RuntimeException { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | public AwsIotRuntimeException(Throwable e) { 26 | super(e); 27 | } 28 | 29 | public AwsIotRuntimeException(String message) { 30 | super(message); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/core/AwsIotTlsConnection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.core; 17 | 18 | import java.security.KeyStore; 19 | import javax.net.SocketFactory; 20 | import javax.net.ssl.SSLSocketFactory; 21 | 22 | import com.amazonaws.services.iot.client.AWSIotException; 23 | import com.amazonaws.services.iot.client.mqtt.AwsIotMqttConnection; 24 | import com.amazonaws.services.iot.client.util.AwsIotTlsSocketFactory; 25 | 26 | /** 27 | * This is a thin layer on top of {@link AwsIotMqttConnection} that provides a 28 | * TLS v1.2 based communication channel to the MQTT implementation. 29 | */ 30 | public class AwsIotTlsConnection extends AwsIotMqttConnection { 31 | 32 | public AwsIotTlsConnection(AbstractAwsIotClient client, KeyStore keyStore, String keyPassword) 33 | throws AWSIotException { 34 | super(client, new AwsIotTlsSocketFactory(keyStore, keyPassword), "ssl://" + client.getClientEndpoint() + ":" + client.getPort()); 35 | } 36 | 37 | public AwsIotTlsConnection(AbstractAwsIotClient client, SSLSocketFactory socketFactory) throws AWSIotException { 38 | super(client, new AwsIotTlsSocketFactory(socketFactory), "ssl://" + client.getClientEndpoint() + ":" + client.getPort()); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/core/AwsIotTopicCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.core; 17 | 18 | import com.amazonaws.services.iot.client.AWSIotMessage; 19 | 20 | /** 21 | * This interface class defines the function called when subscribed message has 22 | * arrived. 23 | */ 24 | public interface AwsIotTopicCallback { 25 | 26 | void onMessage(AWSIotMessage message); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/core/AwsIotWebsocketConnection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.core; 17 | 18 | import java.util.HashSet; 19 | import java.util.Set; 20 | 21 | import com.amazonaws.services.iot.client.auth.CredentialsProvider; 22 | import com.amazonaws.services.iot.client.AWSIotException; 23 | import com.amazonaws.services.iot.client.mqtt.AwsIotMqttConnection; 24 | import com.amazonaws.services.iot.client.util.AwsIotWebSocketUrlSigner; 25 | 26 | /** 27 | * This is a thin layer on top of {@link AwsIotMqttConnection} that provides a 28 | * WebSocket based communication channel to the MQTT implementation. 29 | */ 30 | public class AwsIotWebsocketConnection extends AwsIotMqttConnection { 31 | 32 | private AwsIotWebSocketUrlSigner urlSigner; 33 | 34 | public AwsIotWebsocketConnection(AbstractAwsIotClient client, String awsAccessKeyId, String awsSecretAccessKey) 35 | throws AWSIotException { 36 | this(client, awsAccessKeyId, awsSecretAccessKey, null); 37 | } 38 | 39 | public AwsIotWebsocketConnection(AbstractAwsIotClient client, String awsAccessKeyId, String awsSecretAccessKey, 40 | String sessionToken, String region) throws AWSIotException { 41 | super(client, null, "wss://" + client.getClientEndpoint() + ":443"); 42 | 43 | // Port number must be included in the endpoint for signing otherwise 44 | // the signature verification will fail. This is because the Paho client 45 | // library always includes port number in the host line of the 46 | // HTTP request header, e.g "Host: data.iot.us-east-1.amazonaws.com:443". 47 | urlSigner = new AwsIotWebSocketUrlSigner(client.getClientEndpoint() + ":443", region); 48 | urlSigner.updateCredentials(awsAccessKeyId, awsSecretAccessKey, sessionToken); 49 | } 50 | 51 | public AwsIotWebsocketConnection(AbstractAwsIotClient client, String awsAccessKeyId, String awsSecretAccessKey, 52 | String sessionToken) throws AWSIotException { 53 | //setting the region blank to ensure it's determined from the client Endpoint 54 | this(client, awsAccessKeyId, awsSecretAccessKey, sessionToken, ""); 55 | } 56 | 57 | public AwsIotWebsocketConnection(AbstractAwsIotClient client, CredentialsProvider provider, String region) throws AWSIotException { 58 | super(client, null, "wss://" + client.getClientEndpoint() + ":443"); 59 | 60 | // Port number must be included in the endpoint for signing otherwise 61 | // the signature verification will fail. This is because the Paho client 62 | // library always includes port number in the host line of the 63 | // HTTP request header, e.g "Host: data.iot.us-east-1.amazonaws.com:443". 64 | urlSigner = new AwsIotWebSocketUrlSigner(client.getClientEndpoint() + ":443", provider, region); 65 | } 66 | 67 | @Override 68 | public void updateCredentials(String awsAccessKeyId, String awsSecretAccessKey, String sessionToken) { 69 | urlSigner.updateCredentials(awsAccessKeyId, awsSecretAccessKey, sessionToken); 70 | } 71 | 72 | @Override 73 | public Set getServerUris() { 74 | Set uris = new HashSet<>(); 75 | try { 76 | uris.add(urlSigner.getSignedUrl(null)); 77 | } catch (AWSIotException e) { 78 | throw new AwsIotRuntimeException(e); 79 | } 80 | 81 | return uris; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/mqtt/AwsIotMqttClientListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.mqtt; 17 | 18 | import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; 19 | import org.eclipse.paho.client.mqttv3.MqttCallback; 20 | import org.eclipse.paho.client.mqttv3.MqttMessage; 21 | 22 | import com.amazonaws.services.iot.client.AWSIotMessage; 23 | import com.amazonaws.services.iot.client.AWSIotQos; 24 | import com.amazonaws.services.iot.client.core.AbstractAwsIotClient; 25 | 26 | /** 27 | * This class implements listener functions for client related events from the 28 | * Paho MQTT library. 29 | */ 30 | public class AwsIotMqttClientListener implements MqttCallback { 31 | 32 | private AbstractAwsIotClient client; 33 | 34 | public AwsIotMqttClientListener(AbstractAwsIotClient client) { 35 | this.client = client; 36 | } 37 | 38 | @Override 39 | public void connectionLost(Throwable arg0) { 40 | client.scheduleTask(new Runnable() { 41 | @Override 42 | public void run() { 43 | client.getConnection().onConnectionFailure(); 44 | } 45 | }); 46 | } 47 | 48 | @Override 49 | public void deliveryComplete(IMqttDeliveryToken arg0) { 50 | // Callback is not used 51 | } 52 | 53 | @Override 54 | public void messageArrived(String topic, MqttMessage arg1) throws Exception { 55 | AWSIotMessage message = new AWSIotMessage(topic, AWSIotQos.valueOf(arg1.getQos()), arg1.getPayload()); 56 | client.dispatch(message); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/mqtt/AwsIotMqttConnection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.mqtt; 17 | 18 | import java.util.HashSet; 19 | import java.util.Set; 20 | 21 | import javax.net.SocketFactory; 22 | 23 | import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 24 | import org.eclipse.paho.client.mqttv3.MqttConnectOptions; 25 | import org.eclipse.paho.client.mqttv3.MqttException; 26 | import org.eclipse.paho.client.mqttv3.MqttMessage; 27 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; 28 | 29 | import com.amazonaws.services.iot.client.AWSIotException; 30 | import com.amazonaws.services.iot.client.AWSIotMessage; 31 | import com.amazonaws.services.iot.client.core.AbstractAwsIotClient; 32 | import com.amazonaws.services.iot.client.core.AwsIotConnection; 33 | import com.amazonaws.services.iot.client.core.AwsIotMessageCallback; 34 | import com.amazonaws.services.iot.client.core.AwsIotRetryableException; 35 | 36 | import lombok.Getter; 37 | import lombok.Setter; 38 | 39 | /** 40 | * This class extends {@link AwsIotConnection} to provide the basic MQTT pub/sub 41 | * functionalities using the Paho MQTT library. 42 | */ 43 | @Getter 44 | @Setter 45 | public class AwsIotMqttConnection extends AwsIotConnection { 46 | 47 | // Release Script will replace the version string on release. Refer to codebuild/cd/promote-release.yml 48 | private static final String USERNAME_METRIC_STRING = "?SDK=Java&Version=0.0.1-dev"; 49 | private final SocketFactory socketFactory; 50 | 51 | private MqttAsyncClient mqttClient; 52 | private AwsIotMqttMessageListener messageListener; 53 | private AwsIotMqttClientListener clientListener; 54 | 55 | public AwsIotMqttConnection(AbstractAwsIotClient client, SocketFactory socketFactory, String serverUri) 56 | throws AWSIotException { 57 | super(client); 58 | 59 | this.socketFactory = socketFactory; 60 | 61 | messageListener = new AwsIotMqttMessageListener(client); 62 | clientListener = new AwsIotMqttClientListener(client); 63 | 64 | try { 65 | mqttClient = new MqttAsyncClient(serverUri, client.getClientId(), new MemoryPersistence()); 66 | mqttClient.setCallback(clientListener); 67 | } catch (MqttException e) { 68 | throw new AWSIotException(e); 69 | } 70 | } 71 | 72 | AwsIotMqttConnection(AbstractAwsIotClient client, MqttAsyncClient mqttClient) throws AWSIotException { 73 | super(client); 74 | this.mqttClient = mqttClient; 75 | this.socketFactory = null; 76 | } 77 | 78 | public void openConnection(AwsIotMessageCallback callback) throws AWSIotException { 79 | try { 80 | AwsIotMqttConnectionListener connectionListener = new AwsIotMqttConnectionListener(client, true, callback); 81 | MqttConnectOptions options = buildMqttConnectOptions(client, socketFactory); 82 | mqttClient.connect(options, null, connectionListener); 83 | } catch (MqttException e) { 84 | throw new AWSIotException(e); 85 | } 86 | } 87 | 88 | public void closeConnection(AwsIotMessageCallback callback) throws AWSIotException { 89 | try { 90 | AwsIotMqttConnectionListener connectionListener = new AwsIotMqttConnectionListener(client, false, callback); 91 | mqttClient.disconnect(0, null, connectionListener); 92 | } catch (MqttException e) { 93 | throw new AWSIotException(e); 94 | } 95 | } 96 | 97 | @Override 98 | public void publishMessage(AWSIotMessage message) throws AWSIotException, AwsIotRetryableException { 99 | String topic = message.getTopic(); 100 | MqttMessage mqttMessage = new MqttMessage(message.getPayload()); 101 | mqttMessage.setQos(message.getQos().getValue()); 102 | 103 | try { 104 | mqttClient.publish(topic, mqttMessage, message, messageListener); 105 | } catch (MqttException e) { 106 | if (e.getReasonCode() == MqttException.REASON_CODE_CLIENT_NOT_CONNECTED) { 107 | throw new AwsIotRetryableException(e); 108 | } else { 109 | throw new AWSIotException(e); 110 | } 111 | } 112 | } 113 | 114 | @Override 115 | public void subscribeTopic(AWSIotMessage message) throws AWSIotException, AwsIotRetryableException { 116 | try { 117 | mqttClient.subscribe(message.getTopic(), message.getQos().getValue(), message, messageListener); 118 | } catch (MqttException e) { 119 | if (e.getReasonCode() == MqttException.REASON_CODE_CLIENT_NOT_CONNECTED) { 120 | throw new AwsIotRetryableException(e); 121 | } else { 122 | throw new AWSIotException(e); 123 | } 124 | } 125 | } 126 | 127 | @Override 128 | public void unsubscribeTopic(AWSIotMessage message) throws AWSIotException, AwsIotRetryableException { 129 | try { 130 | mqttClient.unsubscribe(message.getTopic(), message, messageListener); 131 | } catch (MqttException e) { 132 | if (e.getReasonCode() == MqttException.REASON_CODE_CLIENT_NOT_CONNECTED) { 133 | throw new AwsIotRetryableException(e); 134 | } else { 135 | throw new AWSIotException(e); 136 | } 137 | } 138 | } 139 | 140 | public Set getServerUris() { 141 | return new HashSet<>(); 142 | } 143 | 144 | private MqttConnectOptions buildMqttConnectOptions(AbstractAwsIotClient client, SocketFactory socketFactory) { 145 | MqttConnectOptions options = new MqttConnectOptions(); 146 | 147 | options.setSocketFactory(socketFactory); 148 | options.setCleanSession(client.isCleanSession()); 149 | options.setConnectionTimeout(client.getConnectionTimeout() / 1000); 150 | options.setKeepAliveInterval(client.getKeepAliveInterval() / 1000); 151 | if(client.isClientEnableMetrics()) { 152 | options.setUserName(USERNAME_METRIC_STRING); 153 | } 154 | 155 | Set serverUris = getServerUris(); 156 | if (serverUris != null && !serverUris.isEmpty()) { 157 | String[] uriArray = new String[serverUris.size()]; 158 | serverUris.toArray(uriArray); 159 | options.setServerURIs(uriArray); 160 | } 161 | 162 | if (client.getWillMessage() != null) { 163 | AWSIotMessage message = client.getWillMessage(); 164 | 165 | options.setWill(message.getTopic(), message.getPayload(), message.getQos().getValue(), false); 166 | } 167 | 168 | return options; 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/mqtt/AwsIotMqttConnectionListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.mqtt; 17 | 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | import org.eclipse.paho.client.mqttv3.IMqttActionListener; 22 | import org.eclipse.paho.client.mqttv3.IMqttToken; 23 | 24 | import com.amazonaws.services.iot.client.core.AbstractAwsIotClient; 25 | import com.amazonaws.services.iot.client.core.AwsIotMessageCallback; 26 | 27 | /** 28 | * This class implements listener functions for the connection events from the 29 | * Paho MQTT library. 30 | */ 31 | public class AwsIotMqttConnectionListener implements IMqttActionListener { 32 | 33 | private static final Logger LOGGER = Logger.getLogger(AwsIotMqttConnectionListener.class.getName()); 34 | 35 | private final AbstractAwsIotClient client; 36 | private final boolean isConnect; 37 | private final AwsIotMessageCallback userCallback; 38 | 39 | public AwsIotMqttConnectionListener(AbstractAwsIotClient client, boolean isConnect, 40 | AwsIotMessageCallback userCallback) { 41 | this.client = client; 42 | this.isConnect = isConnect; 43 | this.userCallback = userCallback; 44 | } 45 | 46 | @Override 47 | public void onSuccess(IMqttToken arg0) { 48 | client.scheduleTask(new Runnable() { 49 | @Override 50 | public void run() { 51 | if (isConnect) { 52 | client.getConnection().onConnectionSuccess(); 53 | } else { 54 | client.getConnection().onConnectionClosed(); 55 | } 56 | if (userCallback != null) { 57 | userCallback.onSuccess(); 58 | } 59 | } 60 | }); 61 | } 62 | 63 | @Override 64 | public void onFailure(IMqttToken arg0, Throwable arg1) { 65 | LOGGER.log(Level.WARNING, (isConnect ? "Connect" : "Disconnect") + " request failure", arg1); 66 | 67 | client.scheduleTask(new Runnable() { 68 | @Override 69 | public void run() { 70 | if (isConnect) { 71 | client.getConnection().onConnectionFailure(); 72 | } else { 73 | client.getConnection().onConnectionClosed(); 74 | } 75 | if (userCallback != null) { 76 | userCallback.onFailure(); 77 | } 78 | } 79 | }); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/mqtt/AwsIotMqttMessageListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.mqtt; 17 | 18 | import java.util.logging.Logger; 19 | 20 | import org.eclipse.paho.client.mqttv3.IMqttActionListener; 21 | import org.eclipse.paho.client.mqttv3.IMqttToken; 22 | import org.eclipse.paho.client.mqttv3.internal.wire.MqttSuback; 23 | 24 | import com.amazonaws.services.iot.client.AWSIotMessage; 25 | import com.amazonaws.services.iot.client.core.AbstractAwsIotClient; 26 | 27 | /** 28 | * This class implements listener functions for the message events from the Paho 29 | * MQTT library. 30 | */ 31 | public class AwsIotMqttMessageListener implements IMqttActionListener { 32 | 33 | private static final Logger LOGGER = Logger.getLogger(AwsIotMqttMessageListener.class.getName()); 34 | 35 | private static final int SUB_ACK_RETURN_CODE_FAILURE = 0x80; 36 | 37 | private AbstractAwsIotClient client; 38 | 39 | public AwsIotMqttMessageListener(AbstractAwsIotClient client) { 40 | this.client = client; 41 | } 42 | 43 | @Override 44 | public void onSuccess(IMqttToken token) { 45 | final AWSIotMessage message = (AWSIotMessage) token.getUserContext(); 46 | if (message == null) { 47 | return; 48 | } 49 | 50 | boolean forceFailure = false; 51 | if (token.getResponse() instanceof MqttSuback) { 52 | MqttSuback subAck = (MqttSuback) token.getResponse(); 53 | int qos[] = subAck.getGrantedQos(); 54 | for (int i = 0; i < qos.length; i++) { 55 | if (qos[i] == SUB_ACK_RETURN_CODE_FAILURE) { 56 | LOGGER.warning("Request failed: likely due to too many subscriptions or policy violations"); 57 | forceFailure = true; 58 | break; 59 | } 60 | } 61 | } 62 | 63 | final boolean isSuccess = !forceFailure; 64 | client.scheduleTask(new Runnable() { 65 | @Override 66 | public void run() { 67 | if (isSuccess) { 68 | message.onSuccess(); 69 | } else { 70 | message.onFailure(); 71 | } 72 | } 73 | }); 74 | } 75 | 76 | @Override 77 | public void onFailure(IMqttToken token, Throwable cause) { 78 | final AWSIotMessage message = (AWSIotMessage) token.getUserContext(); 79 | if (message == null) { 80 | LOGGER.warning("Request failed: " + token.getException()); 81 | return; 82 | } 83 | 84 | LOGGER.warning("Request failed for topic " + message.getTopic() + ": " + token.getException()); 85 | client.scheduleTask(new Runnable() { 86 | @Override 87 | public void run() { 88 | message.onFailure(); 89 | } 90 | }); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/shadow/AwsIotDeviceCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.shadow; 17 | 18 | import java.util.logging.Logger; 19 | 20 | import com.amazonaws.services.iot.client.AWSIotException; 21 | import com.amazonaws.services.iot.client.AWSIotMessage; 22 | import com.amazonaws.services.iot.client.AWSIotTimeoutException; 23 | import com.amazonaws.services.iot.client.core.AwsIotCompletion; 24 | import com.amazonaws.services.iot.client.shadow.AwsIotDeviceCommandManager.Command; 25 | 26 | import lombok.AccessLevel; 27 | import lombok.Getter; 28 | import lombok.Setter; 29 | 30 | /** 31 | * This is a helper class that can be used to manage the execution result of a 32 | * shadow command, i.e. get, update, and delete. It makes sure that the command 33 | * is not published until the subscription requests for the acknowledgment 34 | * topics, namely accepted and rejected, have completed successfully. 35 | * 36 | * @see com.amazonaws.services.iot.client.core.AwsIotCompletion 37 | */ 38 | @Getter 39 | @Setter 40 | public class AwsIotDeviceCommand extends AwsIotCompletion { 41 | 42 | private static final Logger LOGGER = Logger.getLogger(AwsIotDeviceCommand.class.getName()); 43 | 44 | private final AwsIotDeviceCommandManager commandManager; 45 | private final Command command; 46 | private final String commandId; 47 | 48 | private AWSIotMessage response; 49 | 50 | @Setter(AccessLevel.NONE) 51 | private Boolean requestSent; 52 | 53 | public AwsIotDeviceCommand(AwsIotDeviceCommandManager commandManager, Command command, String commandId, 54 | AWSIotMessage request, long commandTimeout, boolean isAsync) { 55 | super(request, commandTimeout, isAsync); 56 | this.commandManager = commandManager; 57 | this.command = command; 58 | this.commandId = commandId; 59 | this.requestSent = false; 60 | } 61 | 62 | public void put(AbstractAwsIotDevice device) throws AWSIotException { 63 | if (device.isCommandReady(command)) { 64 | _put(device); 65 | } else { 66 | LOGGER.info("Request is pending: " + command.name() + "/" + commandId); 67 | } 68 | } 69 | 70 | public String get(AbstractAwsIotDevice device) throws AWSIotException, AWSIotTimeoutException { 71 | super.get(device.getClient()); 72 | return (response != null) ? response.getStringPayload() : null; 73 | } 74 | 75 | public boolean onReady(AbstractAwsIotDevice device) { 76 | try { 77 | LOGGER.info("Request is resumed: " + command.name() + "/" + commandId); 78 | _put(device); 79 | return true; 80 | } catch (AWSIotException e) { 81 | return false; 82 | } 83 | } 84 | 85 | @Override 86 | public void onSuccess() { 87 | // first callback is for the command ack, which we ignore 88 | if (response == null) { 89 | return; 90 | } else { 91 | request.setPayload(response.getPayload()); 92 | } 93 | 94 | super.onSuccess(); 95 | } 96 | 97 | @Override 98 | public void onFailure() { 99 | super.onFailure(); 100 | } 101 | 102 | @Override 103 | public void onTimeout() { 104 | commandManager.onCommandTimeout(this); 105 | super.onTimeout(); 106 | } 107 | 108 | private void _put(AbstractAwsIotDevice device) throws AWSIotException { 109 | synchronized (this) { 110 | if (requestSent) { 111 | LOGGER.warning("Request was already sent: " + command.name() + "/" + commandId); 112 | return; 113 | } else { 114 | requestSent = true; 115 | } 116 | } 117 | 118 | device.getClient().publish(this, timeout); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/shadow/AwsIotDeviceCommandAckListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.shadow; 17 | 18 | import java.util.logging.Logger; 19 | 20 | import com.amazonaws.services.iot.client.AWSIotMessage; 21 | import com.amazonaws.services.iot.client.AWSIotQos; 22 | import com.amazonaws.services.iot.client.AWSIotTopic; 23 | 24 | /** 25 | * This class extends {@link AWSIotTopic} to provide customized callback 26 | * functions for the subscription requests of the shadow commands. 27 | */ 28 | public class AwsIotDeviceCommandAckListener extends AWSIotTopic { 29 | 30 | private static final Logger LOGGER = Logger.getLogger(AwsIotDeviceCommandAckListener.class.getName()); 31 | 32 | private final AbstractAwsIotDevice device; 33 | 34 | public AwsIotDeviceCommandAckListener(String topic, AWSIotQos qos, AbstractAwsIotDevice device) { 35 | super(topic, qos); 36 | this.device = device; 37 | } 38 | 39 | @Override 40 | public void onMessage(AWSIotMessage message) { 41 | device.onCommandAck(message); 42 | } 43 | 44 | @Override 45 | public void onSuccess() { 46 | device.onSubscriptionAck(topic, true); 47 | } 48 | 49 | @Override 50 | public void onFailure() { 51 | LOGGER.warning("Failed to subscribe to device topic " + topic); 52 | device.onSubscriptionAck(topic, false); 53 | } 54 | 55 | @Override 56 | public void onTimeout() { 57 | LOGGER.warning("Timeout when subscribing to device topic " + topic); 58 | device.onSubscriptionAck(topic, false); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/shadow/AwsIotDeviceDeltaListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.shadow; 17 | 18 | import java.io.IOException; 19 | import java.util.logging.Logger; 20 | 21 | import com.amazonaws.services.iot.client.AWSIotMessage; 22 | import com.amazonaws.services.iot.client.AWSIotQos; 23 | import com.amazonaws.services.iot.client.AWSIotTopic; 24 | import com.fasterxml.jackson.databind.JsonNode; 25 | 26 | /** 27 | * This class extends {@link AWSIotTopic} to provide a callback function for 28 | * receiving the shadow delta updates. 29 | */ 30 | public class AwsIotDeviceDeltaListener extends AWSIotTopic { 31 | 32 | private static final Logger LOGGER = Logger.getLogger(AwsIotDeviceDeltaListener.class.getName()); 33 | 34 | private final AbstractAwsIotDevice device; 35 | 36 | public AwsIotDeviceDeltaListener(String topic, AWSIotQos qos, AbstractAwsIotDevice device) { 37 | super(topic, qos); 38 | this.device = device; 39 | } 40 | 41 | @Override 42 | public void onMessage(AWSIotMessage message) { 43 | String payload = message.getStringPayload(); 44 | if (payload == null) { 45 | LOGGER.warning("Received empty delta for device " + device.getThingName()); 46 | return; 47 | } 48 | 49 | JsonNode rootNode; 50 | try { 51 | rootNode = device.getJsonObjectMapper().readTree(payload); 52 | if (!rootNode.isObject()) { 53 | throw new IOException(); 54 | } 55 | } catch (IOException e) { 56 | LOGGER.warning("Received invalid delta for device " + device.getThingName()); 57 | return; 58 | } 59 | 60 | if (device.enableVersioning) { 61 | JsonNode node = rootNode.get("version"); 62 | if (node == null) { 63 | LOGGER.warning("Missing version field in delta for device " + device.getThingName()); 64 | return; 65 | } 66 | 67 | long receivedVersion = node.longValue(); 68 | long localVersion = device.getLocalVersion().get(); 69 | if (receivedVersion < localVersion) { 70 | LOGGER.warning("An old version of delta received for " + device.getThingName() + ", local " 71 | + localVersion + ", received " + receivedVersion); 72 | return; 73 | } 74 | 75 | device.getLocalVersion().set(receivedVersion); 76 | LOGGER.info("Local version number updated to " + receivedVersion); 77 | } 78 | 79 | JsonNode node = rootNode.get("state"); 80 | if (node == null) { 81 | LOGGER.warning("Missing state field in delta for device " + device.getThingName()); 82 | return; 83 | } 84 | device.onShadowUpdate(node.toString()); 85 | } 86 | 87 | @Override 88 | public void onSuccess() { 89 | } 90 | 91 | @Override 92 | public void onFailure() { 93 | LOGGER.warning("Failed to subscribe to device topic " + topic); 94 | } 95 | 96 | @Override 97 | public void onTimeout() { 98 | LOGGER.warning("Timeout when subscribing to device topic " + topic); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/shadow/AwsIotDeviceReportMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.shadow; 17 | 18 | import java.util.logging.Logger; 19 | 20 | import com.amazonaws.services.iot.client.AWSIotDeviceErrorCode; 21 | import com.amazonaws.services.iot.client.AWSIotMessage; 22 | import com.amazonaws.services.iot.client.AWSIotQos; 23 | 24 | public class AwsIotDeviceReportMessage extends AWSIotMessage { 25 | 26 | private static final Logger LOGGER = Logger.getLogger(AwsIotDeviceReportMessage.class.getName()); 27 | 28 | private final AbstractAwsIotDevice device; 29 | private final long reportVersion; 30 | 31 | public AwsIotDeviceReportMessage(String topic, AWSIotQos qos, long reportVersion, String jsonState, 32 | AbstractAwsIotDevice device) { 33 | super(topic, qos, jsonState); 34 | this.device = device; 35 | this.reportVersion = reportVersion; 36 | } 37 | 38 | @Override 39 | public void onSuccess() { 40 | // increment local version only if it hasn't be updated 41 | device.getLocalVersion().compareAndSet(reportVersion, reportVersion + 1); 42 | } 43 | 44 | @Override 45 | public void onFailure() { 46 | if (AWSIotDeviceErrorCode.CONFLICT.equals(errorCode)) { 47 | LOGGER.warning("Device version conflict, restart version synchronization"); 48 | device.startVersionSync(); 49 | } else { 50 | LOGGER.warning("Failed to publish device report: " + errorMessage); 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/shadow/AwsIotDeviceSyncMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.shadow; 17 | 18 | import java.io.IOException; 19 | import java.util.logging.Logger; 20 | 21 | import com.amazonaws.services.iot.client.AWSIotDeviceErrorCode; 22 | import com.amazonaws.services.iot.client.AWSIotMessage; 23 | import com.amazonaws.services.iot.client.AWSIotQos; 24 | 25 | public class AwsIotDeviceSyncMessage extends AWSIotMessage { 26 | 27 | private static final Logger LOGGER = Logger.getLogger(AwsIotDeviceSyncMessage.class.getName()); 28 | 29 | private final AbstractAwsIotDevice device; 30 | 31 | public AwsIotDeviceSyncMessage(String topic, AWSIotQos qos, AbstractAwsIotDevice device) { 32 | super(topic, qos); 33 | this.device = device; 34 | } 35 | 36 | @Override 37 | public void onSuccess() { 38 | if (payload != null) { 39 | try { 40 | long version = AwsIotJsonDeserializer.deserializeVersion(device, getStringPayload()); 41 | if (version > 0) { 42 | LOGGER.info("Received shadow version number: " + version); 43 | 44 | boolean updated = device.getLocalVersion().compareAndSet(-1, version); 45 | if (!updated) { 46 | LOGGER.warning( 47 | "Local version not updated likely because newer version recieved from shadow update"); 48 | } 49 | } 50 | } catch (IOException e) { 51 | LOGGER.warning("Device update error: " + e.getMessage()); 52 | } 53 | } 54 | } 55 | 56 | @Override 57 | public void onFailure() { 58 | if (AWSIotDeviceErrorCode.NOT_FOUND.equals(errorCode)) { 59 | LOGGER.info("No shadow document found, reset local version to 0"); 60 | device.getLocalVersion().set(0); 61 | } else { 62 | LOGGER.warning("Failed to get shadow version: " + errorMessage); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/shadow/AwsIotJsonDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.shadow; 17 | 18 | import java.io.IOException; 19 | import java.lang.reflect.Field; 20 | import java.lang.reflect.InvocationTargetException; 21 | import java.lang.reflect.Method; 22 | import java.util.Iterator; 23 | 24 | import com.fasterxml.jackson.databind.JsonNode; 25 | import com.fasterxml.jackson.databind.ObjectMapper; 26 | 27 | /** 28 | * This is a customized JSON deserializer for deserializing the delta update 29 | * document from the shadow. 30 | */ 31 | public class AwsIotJsonDeserializer { 32 | 33 | public static void deserialize(AbstractAwsIotDevice device, String jsonState) throws IOException { 34 | ObjectMapper jsonObjectMapper = device.getJsonObjectMapper(); 35 | 36 | JsonNode node = jsonObjectMapper.readTree(jsonState); 37 | if (node == null) { 38 | throw new IOException("Invalid delta update received for " + device.getThingName()); 39 | } 40 | 41 | for (Iterator it = node.fieldNames(); it.hasNext();) { 42 | String property = it.next(); 43 | Field field = device.getUpdatableProperties().get(property); 44 | JsonNode fieldNode = node.get(property); 45 | if (field == null || fieldNode == null) { 46 | continue; 47 | } 48 | 49 | updateDeviceProperty(jsonObjectMapper, fieldNode, device, field); 50 | } 51 | } 52 | 53 | public static long deserializeVersion(AbstractAwsIotDevice device, String jsonState) throws IOException { 54 | ObjectMapper jsonObjectMapper = device.getJsonObjectMapper(); 55 | 56 | JsonNode node = jsonObjectMapper.readTree(jsonState); 57 | if (node == null) { 58 | throw new IOException("Invalid shadow document received for " + device.getThingName()); 59 | } 60 | 61 | JsonNode versionNode = node.get("version"); 62 | if (versionNode == null) { 63 | throw new IOException("Missing version field from shadow document for " + device.getThingName()); 64 | } 65 | 66 | return versionNode.asLong(); 67 | } 68 | 69 | private static void updateDeviceProperty(ObjectMapper jsonObjectMapper, JsonNode node, AbstractAwsIotDevice device, 70 | Field field) throws IOException { 71 | Object value = jsonObjectMapper.treeToValue(node, field.getType()); 72 | invokeSetterMethod(device, field.getName(), field.getType(), value); 73 | } 74 | 75 | private static void invokeSetterMethod(Object target, String name, Class type, Object value) throws IOException { 76 | String setter = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1); 77 | 78 | Method method; 79 | try { 80 | method = target.getClass().getMethod(setter, type); 81 | } catch (NoSuchMethodException | SecurityException e) { 82 | throw new IllegalArgumentException(e); 83 | } 84 | 85 | try { 86 | method.invoke(target, value); 87 | } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 88 | throw new IOException(e); 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/shadow/AwsIotJsonSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.shadow; 17 | 18 | import java.io.IOException; 19 | import java.lang.reflect.Field; 20 | import java.lang.reflect.InvocationTargetException; 21 | import java.lang.reflect.Method; 22 | 23 | import com.fasterxml.jackson.core.JsonGenerator; 24 | import com.fasterxml.jackson.core.JsonProcessingException; 25 | import com.fasterxml.jackson.databind.JsonSerializer; 26 | import com.fasterxml.jackson.databind.SerializerProvider; 27 | 28 | /** 29 | * This is a customized JSON serializer for the Jackson databind module. It is 30 | * used for serializing the device properties to be reported to the shadow. 31 | */ 32 | public class AwsIotJsonSerializer extends JsonSerializer { 33 | 34 | @Override 35 | public void serialize(AbstractAwsIotDevice device, JsonGenerator generator, SerializerProvider provider) 36 | throws IOException, JsonProcessingException { 37 | generator.writeStartObject(); 38 | 39 | try { 40 | for (String property : device.getReportedProperties().keySet()) { 41 | Field field = device.getReportedProperties().get(property); 42 | 43 | Object value = invokeGetterMethod(device, field); 44 | generator.writeObjectField(property, value); 45 | } 46 | } catch (IllegalArgumentException e) { 47 | throw new IOException(e); 48 | } 49 | 50 | generator.writeEndObject(); 51 | } 52 | 53 | private static Object invokeGetterMethod(Object target, Field field) throws IOException { 54 | String fieldName = Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1); 55 | String getter = "get" + fieldName; 56 | 57 | Method method; 58 | try { 59 | method = target.getClass().getMethod(getter); 60 | } catch (NoSuchMethodException | SecurityException e) { 61 | if (e instanceof NoSuchMethodException && boolean.class.equals(field.getType())) { 62 | getter = "is" + fieldName; 63 | try { 64 | method = target.getClass().getMethod(getter); 65 | } catch (NoSuchMethodException | SecurityException ie) { 66 | throw new IllegalArgumentException(ie); 67 | } 68 | } else { 69 | throw new IllegalArgumentException(e); 70 | } 71 | } 72 | 73 | Object value; 74 | try { 75 | value = method.invoke(target); 76 | } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 77 | throw new IOException(e); 78 | } 79 | return value; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/util/AwsIotTlsSocketFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.services.iot.client.util; 17 | 18 | import java.io.IOException; 19 | import java.net.InetAddress; 20 | import java.net.Socket; 21 | import java.net.UnknownHostException; 22 | import java.security.KeyManagementException; 23 | import java.security.KeyStore; 24 | 25 | import java.security.KeyStoreException; 26 | import java.security.NoSuchAlgorithmException; 27 | import java.security.UnrecoverableKeyException; 28 | 29 | import javax.net.ssl.KeyManagerFactory; 30 | import javax.net.ssl.SSLContext; 31 | import javax.net.ssl.SSLParameters; 32 | import javax.net.ssl.SSLSocket; 33 | import javax.net.ssl.SSLSocketFactory; 34 | 35 | import com.amazonaws.services.iot.client.AWSIotException; 36 | 37 | /** 38 | * This class extends {@link SSLSocketFactory} to enforce TLS v1.2 to be used 39 | * for SSL sockets created by the library. 40 | */ 41 | public class AwsIotTlsSocketFactory extends SSLSocketFactory { 42 | private static final String TLS_V_1_2 = "TLSv1.2"; 43 | 44 | /** 45 | * SSL Socket Factory A SSL socket factory is created and passed into this 46 | * class which decorates it to enable TLS 1.2 when sockets are created. 47 | */ 48 | private final SSLSocketFactory sslSocketFactory; 49 | 50 | public AwsIotTlsSocketFactory(KeyStore keyStore, String keyPassword) throws AWSIotException { 51 | try { 52 | SSLContext context = SSLContext.getInstance(TLS_V_1_2); 53 | 54 | KeyManagerFactory managerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 55 | managerFactory.init(keyStore, keyPassword.toCharArray()); 56 | context.init(managerFactory.getKeyManagers(), null, null); 57 | 58 | sslSocketFactory = context.getSocketFactory(); 59 | } catch (NoSuchAlgorithmException | KeyStoreException | UnrecoverableKeyException | KeyManagementException e) { 60 | throw new AWSIotException(e); 61 | } 62 | } 63 | 64 | public AwsIotTlsSocketFactory(SSLSocketFactory sslSocketFactory) { 65 | this.sslSocketFactory = sslSocketFactory; 66 | } 67 | 68 | @Override 69 | public String[] getDefaultCipherSuites() { 70 | return sslSocketFactory.getDefaultCipherSuites(); 71 | } 72 | 73 | @Override 74 | public String[] getSupportedCipherSuites() { 75 | return sslSocketFactory.getSupportedCipherSuites(); 76 | } 77 | 78 | @Override 79 | public Socket createSocket() throws IOException { 80 | return ensureTls(sslSocketFactory.createSocket()); 81 | } 82 | 83 | @Override 84 | public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { 85 | return ensureTls(sslSocketFactory.createSocket(s, host, port, autoClose)); 86 | } 87 | 88 | @Override 89 | public Socket createSocket(String host, int port) throws IOException, UnknownHostException { 90 | return ensureTls(sslSocketFactory.createSocket(host, port)); 91 | } 92 | 93 | @Override 94 | public Socket createSocket(String host, int port, InetAddress localHost, int localPort) 95 | throws IOException, UnknownHostException { 96 | return ensureTls(sslSocketFactory.createSocket(host, port, localHost, localPort)); 97 | } 98 | 99 | @Override 100 | public Socket createSocket(InetAddress host, int port) throws IOException { 101 | return ensureTls(sslSocketFactory.createSocket(host, port)); 102 | } 103 | 104 | @Override 105 | public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) 106 | throws IOException { 107 | return ensureTls(sslSocketFactory.createSocket(address, port, localAddress, localPort)); 108 | } 109 | 110 | /** 111 | * Enable TLS 1.2 on any socket created by the underlying SSL Socket 112 | * Factory. 113 | * 114 | * @param socket 115 | * newly created socket which may not have TLS 1.2 enabled. 116 | * @return TLS 1.2 enabled socket. 117 | */ 118 | private Socket ensureTls(Socket socket) { 119 | if (socket != null && (socket instanceof SSLSocket)) { 120 | ((SSLSocket) socket).setEnabledProtocols(new String[] { TLS_V_1_2 }); 121 | 122 | // Ensure hostname is validated againt the CN in the certificate 123 | SSLParameters sslParams = new SSLParameters(); 124 | sslParams.setEndpointIdentificationAlgorithm("HTTPS"); 125 | ((SSLSocket) socket).setSSLParameters(sslParams); 126 | } 127 | return socket; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/AWSIotDeviceErrorCodeTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | public class AWSIotDeviceErrorCodeTest { 8 | 9 | @Test 10 | public void testValueOf() { 11 | assertEquals(AWSIotDeviceErrorCode.BAD_REQUEST, AWSIotDeviceErrorCode.valueOf(400)); 12 | } 13 | 14 | @Test 15 | public void testgetValue() { 16 | assertEquals(400, AWSIotDeviceErrorCode.BAD_REQUEST.getValue()); 17 | } 18 | 19 | @Test 20 | public void testInvalidValue() { 21 | assertNull(AWSIotDeviceErrorCode.valueOf(10)); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/AWSIotDeviceIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.UnsupportedEncodingException; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.logging.Level; 9 | import java.util.logging.Logger; 10 | 11 | import org.junit.After; 12 | import org.junit.Before; 13 | import org.junit.BeforeClass; 14 | import org.junit.Test; 15 | import java.util.UUID; 16 | 17 | public class AWSIotDeviceIntegrationTest implements TestDeviceNotifier { 18 | 19 | private static final Logger LOGGER = Logger.getLogger(AWSIotDeviceIntegrationTest.class.getName()); 20 | private static final String UPDATE_TOPIC = "$aws/things/?/shadow/update"; 21 | // Added UID to distinguish concurrent running test 22 | private static final String THING_NAME = System.getProperty("thingName") + UUID.randomUUID().toString(); 23 | private static final String STABILITY_TEST_ITERATIONS = System.getProperty("stabilityTestIterations"); 24 | 25 | private AWSIotMqttClient client; 26 | private TestDevice device; 27 | 28 | @BeforeClass 29 | public static void init() { 30 | AWSIotMqttClientIntegrationUtil.enableConsoleLogging(LOGGER); 31 | } 32 | 33 | @Before 34 | public void setup() { 35 | client = AWSIotMqttClientIntegrationUtil.getClient(); 36 | assertNotNull("Client not initialized likely due to required system properties not being provided", client); 37 | assertNotNull("thingName was not provided", THING_NAME); 38 | } 39 | 40 | @After 41 | public void cleanup() { 42 | try { 43 | if (client != null) { 44 | client.disconnect(500); 45 | client = null; 46 | } 47 | } catch (Exception e) { 48 | LOGGER.log(Level.WARNING, "disconnect failed with exception", e); 49 | } 50 | } 51 | 52 | @Test 53 | public void testDeviceReport() throws AWSIotException, InterruptedException, UnsupportedEncodingException { 54 | String serailNumber = "123-456-789"; 55 | Float threshold = Float.valueOf(0f); 56 | Map sensors = new HashMap<>(); 57 | sensors.put("sensor-0", Float.valueOf(0f)); 58 | sensors.put("sensor-1", Float.valueOf(0f)); 59 | sensors.put("sensor-2", Float.valueOf(0f)); 60 | 61 | device = new TestDevice(THING_NAME, serailNumber, threshold, sensors); 62 | device.setReportInterval(1000); 63 | client.attach(device); 64 | 65 | client.connect(); 66 | 67 | device.delete(); 68 | 69 | String deltaTopic = UPDATE_TOPIC.replace("?", THING_NAME); 70 | TestTopic topic = new TestTopic(deltaTopic, null); 71 | client.subscribe(topic); 72 | 73 | Thread.sleep(2000); 74 | 75 | assertNotNull(topic.lastPayload); 76 | String update = new String(topic.lastPayload, "UTF-8"); 77 | assertTrue(update.contains("\"threshold\":0.0")); 78 | assertTrue(update.contains("\"serialNumber\":\"123-456-789\"")); 79 | assertTrue(update.contains("\"sensor-0\":0.0")); 80 | assertTrue(update.contains("\"sensor-1\":0.0")); 81 | assertTrue(update.contains("\"sensor-2\":0.0")); 82 | } 83 | 84 | @Test 85 | public void testDeviceUpdate() throws AWSIotException, InterruptedException, UnsupportedEncodingException { 86 | String serailNumber = "123-456-789"; 87 | Float threshold = Float.valueOf(0f); 88 | Map sensors = new HashMap<>(); 89 | sensors.put("sensor-0", Float.valueOf(0f)); 90 | sensors.put("sensor-1", Float.valueOf(0f)); 91 | sensors.put("sensor-2", Float.valueOf(0f)); 92 | 93 | device = new TestDevice(THING_NAME, serailNumber, threshold, sensors); 94 | device.setReportInterval(1000); 95 | client.attach(device); 96 | 97 | client.connect(); 98 | 99 | device.delete(); 100 | 101 | Thread.sleep(1000); 102 | 103 | String desired = "{\"state\":{\"desired\":{\"threshold\":3.0}}}"; 104 | device.update(desired); 105 | 106 | Thread.sleep(2000); 107 | assertEquals(Float.valueOf(3.0f), device.getThreshold()); 108 | } 109 | 110 | @Test 111 | public void testDeviceReportAndUpdate() throws AWSIotException, InterruptedException, UnsupportedEncodingException { 112 | String serailNumber = "123-456-789"; 113 | Float threshold = Float.valueOf(0f); 114 | Map sensors = new HashMap<>(); 115 | sensors.put("sensor-0", Float.valueOf(0f)); 116 | sensors.put("sensor-1", Float.valueOf(0f)); 117 | sensors.put("sensor-2", Float.valueOf(0f)); 118 | 119 | device = new TestDevice(THING_NAME, serailNumber, threshold, sensors); 120 | device.setReportInterval(1000); 121 | device.addNotifier(this); 122 | device.startMonitoring(); 123 | 124 | client.attach(device); 125 | 126 | client.connect(); 127 | 128 | device.delete(); 129 | 130 | String desired = "{\"state\":{\"desired\":{\"threshold\":-10.0}}}"; 131 | device.update(desired); 132 | 133 | Thread.sleep(3000); 134 | device.stopMonitoring(); 135 | 136 | assertEquals(Float.valueOf(-10f), device.getSensorValue("sensor-0")); 137 | assertEquals(Float.valueOf(-10f), device.getSensorValue("sensor-1")); 138 | assertEquals(Float.valueOf(-10f), device.getSensorValue("sensor-2")); 139 | 140 | String state = device.get(); 141 | assertTrue(state.contains("\"sensor-0\":-10.0")); 142 | assertTrue(state.contains("\"sensor-1\":-10.0")); 143 | assertTrue(state.contains("\"sensor-2\":-10.0")); 144 | } 145 | 146 | @Test 147 | public void testDeviceStability() throws AWSIotException, InterruptedException, UnsupportedEncodingException { 148 | String serailNumber = "123-456-789"; 149 | Float threshold = Float.valueOf(0f); 150 | Map sensors = new HashMap<>(); 151 | sensors.put("sensor-0", Float.valueOf(0f)); 152 | sensors.put("sensor-1", Float.valueOf(0f)); 153 | sensors.put("sensor-2", Float.valueOf(0f)); 154 | 155 | device = new TestDevice(THING_NAME, serailNumber, threshold, sensors); 156 | device.setReportInterval(1000); 157 | device.addNotifier(this); 158 | device.startMonitoring(); 159 | 160 | client.attach(device); 161 | 162 | AWSIotMessage willMessage = new AWSIotMessage("test/disconnect", AWSIotQos.QOS0, client.getClientId()); 163 | client.setWillMessage(willMessage); 164 | client.connect(); 165 | 166 | device.delete(); 167 | 168 | Float value = Float.valueOf(0.0f); 169 | long testIterations = STABILITY_TEST_ITERATIONS == null ? 10 : Long.parseLong(STABILITY_TEST_ITERATIONS); 170 | while (testIterations-- > 0) { 171 | value -= 10.0f; 172 | device.update("{\"state\":{\"desired\":{\"threshold\":" + value.toString() + "}}}"); 173 | Thread.sleep(3000); 174 | } 175 | 176 | String state = device.get(); 177 | assertTrue(state.contains("\"sensor-0\":" + value)); 178 | assertTrue(state.contains("\"sensor-1\":" + value)); 179 | assertTrue(state.contains("\"sensor-2\":" + value)); 180 | } 181 | 182 | @Override 183 | public void reportAlarm(String sensorName, Float sensorValue, Float threshold) { 184 | device.setSensorValue(sensorName, sensorValue - 1.0f); 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/AWSIotMessageTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Arrays; 6 | 7 | import org.junit.Test; 8 | 9 | public class AWSIotMessageTest { 10 | 11 | @Test 12 | public void testRawPayload() { 13 | byte[] testBytes = "test string".getBytes(); 14 | 15 | AWSIotMessage message = new AWSIotMessage("topic", AWSIotQos.QOS0); 16 | 17 | message.setPayload(testBytes); 18 | 19 | assertTrue(Arrays.equals(testBytes, message.getPayload())); 20 | } 21 | 22 | @Test 23 | public void testBytesToStringPayload() { 24 | byte[] testBytes = "test string".getBytes(); 25 | 26 | AWSIotMessage message = new AWSIotMessage("topic", AWSIotQos.QOS0); 27 | 28 | message.setPayload(testBytes); 29 | 30 | assertEquals("test string", message.getStringPayload()); 31 | } 32 | 33 | @Test 34 | public void testStringSerialization() { 35 | String testString = "test string"; 36 | 37 | AWSIotMessage message = new AWSIotMessage("topic", AWSIotQos.QOS0); 38 | 39 | message.setStringPayload(testString); 40 | 41 | assertEquals(testString, message.getStringPayload()); 42 | } 43 | 44 | @Test 45 | public void testMultiByteStringSerialization() { 46 | byte[] chineseLetterInUtf8 = { (byte) 0xE7, (byte) 0x9A, (byte) 0x84 }; 47 | 48 | AWSIotMessage message = new AWSIotMessage("topic", AWSIotQos.QOS0, chineseLetterInUtf8); 49 | 50 | assertEquals("的", message.getStringPayload()); 51 | } 52 | 53 | @Test 54 | public void testMultiByteStringDeserialization() { 55 | byte[] chineseLetterInUtf8 = { (byte) 0xE7, (byte) 0x9A, (byte) 0x84 }; 56 | 57 | AWSIotMessage message = new AWSIotMessage("topic", AWSIotQos.QOS0, "的"); 58 | 59 | assertTrue(Arrays.equals(chineseLetterInUtf8, message.getPayload())); 60 | } 61 | 62 | @Test 63 | public void testInvalidMultiByteString() { 64 | byte[] chineseLetterInUtf8 = { (byte) 0xE7, (byte) 0x9A }; 65 | 66 | AWSIotMessage message = new AWSIotMessage("topic", AWSIotQos.QOS0, chineseLetterInUtf8); 67 | 68 | assertEquals("�", message.getStringPayload()); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/AWSIotMqttClientIntegrationUtil.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client; 2 | 3 | import static org.junit.Assert.assertNotNull; 4 | import static org.junit.Assert.fail; 5 | 6 | import java.io.FileInputStream; 7 | import java.security.KeyStore; 8 | import java.util.logging.ConsoleHandler; 9 | import java.util.logging.Handler; 10 | import java.util.logging.Level; 11 | import java.util.logging.Logger; 12 | 13 | import com.amazonaws.services.iot.client.CredentialUtil; 14 | 15 | public class AWSIotMqttClientIntegrationUtil { 16 | 17 | private static final String CLIENT_ENDPOINT = System.getProperty("clientEndpoint"); 18 | private static final String CLIENT_ID = System.getProperty("clientId"); 19 | 20 | private static final String AUTH_MODE = System.getProperty("authMode"); 21 | 22 | private static final Boolean IS_WEBSOCKET = Boolean.parseBoolean(System.getProperty("isWebSocket")); 23 | private static final String PUBLIC_MATERIAL = System.getProperty("publicMaterial"); 24 | private static final String PRIVATE_MATERIAL = System.getProperty("privateMaterial"); 25 | private static final String KEYSTORE_FILE = System.getProperty("keystoreFile"); 26 | private static final String KEYSTORE_PASSWORD = System.getProperty("keystorePassword"); 27 | private static final String KEY_PASSWORD = System.getProperty("keyPassword"); 28 | 29 | private static final String LOG_LEVEL = System.getProperty("logLevel"); 30 | 31 | public static void enableConsoleLogging(Logger logger) { 32 | Level level = Level.FINE; 33 | 34 | if (LOG_LEVEL != null) { 35 | level = Level.parse(LOG_LEVEL); 36 | } 37 | 38 | Handler consoleHandler = new ConsoleHandler(); 39 | consoleHandler.setLevel(level); 40 | 41 | logger.addHandler(consoleHandler); 42 | logger.setUseParentHandlers(false); 43 | logger.setLevel(level); 44 | } 45 | 46 | public static AWSIotMqttClient getClient() { 47 | return getClient(""); 48 | } 49 | 50 | public static AWSIotMqttClient getClient(String suffix) { 51 | assertNotNull("Client endpoint not provided", CLIENT_ENDPOINT); 52 | assertNotNull("Client ID not provided", CLIENT_ID); 53 | 54 | AWSIotMqttClient client = getClientFromAutoConfig(suffix); 55 | if (client == null) { 56 | client = getClientFromManualConfig(suffix); 57 | } 58 | 59 | return client; 60 | } 61 | 62 | private static AWSIotMqttClient getClientFromAutoConfig(final String suffix) { 63 | AWSIotMqttClient client = null; 64 | 65 | if (AUTH_MODE != null) { 66 | switch (AUTH_MODE) { 67 | case AuthMode.CERT_AUTH: // CredentialUtil handles cert from odin to generate client as well. : ) 68 | case AuthMode.WSS_SIGV4_AUTH: 69 | client = CredentialUtil.newClient(CLIENT_ENDPOINT, CLIENT_ID + suffix, PUBLIC_MATERIAL, PRIVATE_MATERIAL, IS_WEBSOCKET); 70 | break; 71 | default: 72 | throw new UnsupportedOperationException("No such auth mode supported: " + AUTH_MODE); 73 | } 74 | } 75 | 76 | return client; 77 | } 78 | 79 | private static AWSIotMqttClient getClientFromManualConfig(final String suffix) { 80 | AWSIotMqttClient client = null; 81 | 82 | if (KEYSTORE_FILE != null && KEYSTORE_PASSWORD != null) { 83 | try { 84 | KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 85 | keyStore.load(new FileInputStream(KEYSTORE_FILE), KEYSTORE_PASSWORD.toCharArray()); 86 | 87 | client = new AWSIotMqttClient(CLIENT_ENDPOINT, CLIENT_ID + suffix, keyStore, KEY_PASSWORD); 88 | } catch (Exception e) { 89 | fail("Failed to load keystore file for the integration tests"); 90 | } 91 | } else if (PUBLIC_MATERIAL != null && PRIVATE_MATERIAL != null) { 92 | client = CredentialUtil.newClient(CLIENT_ENDPOINT, CLIENT_ID + suffix, PUBLIC_MATERIAL, PRIVATE_MATERIAL, IS_WEBSOCKET); 93 | } 94 | 95 | return client; 96 | } 97 | 98 | private class AuthMode { 99 | private static final String CERT_AUTH = "CertificateMutualAuthentication"; 100 | private static final String WSS_SIGV4_AUTH = "MqttOverWebSocketSigV4Signing"; 101 | private static final String WSS_CUSTOM_AUTH = "MqttOverWebSocketCustomAuthZ"; // Reserved for custom authZ integ test 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/AWSIotQosTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | public class AWSIotQosTest { 8 | 9 | @Test 10 | public void testValueOf0() { 11 | assertEquals(AWSIotQos.QOS0, AWSIotQos.valueOf(0)); 12 | } 13 | 14 | @Test 15 | public void testValueOf1() { 16 | assertEquals(AWSIotQos.QOS1, AWSIotQos.valueOf(1)); 17 | } 18 | 19 | @Test(expected = IllegalArgumentException.class) 20 | public void testValueOf2() { 21 | AWSIotQos.valueOf(2); 22 | } 23 | 24 | @Test 25 | public void testgetValueOf0() { 26 | assertEquals(0, AWSIotQos.QOS0.getValue()); 27 | } 28 | 29 | @Test 30 | public void testgetValueOf1() { 31 | assertEquals(1, AWSIotQos.QOS1.getValue()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/TestDevice.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.logging.Logger; 9 | 10 | import com.amazonaws.services.iot.client.AWSIotDevice; 11 | import com.amazonaws.services.iot.client.AWSIotDeviceProperty; 12 | 13 | public class TestDevice extends AWSIotDevice { 14 | 15 | private static final Logger LOGGER = Logger.getLogger(AWSIotDeviceIntegrationTest.class.getName()); 16 | 17 | @AWSIotDeviceProperty(allowUpdate = false) 18 | private String serialNumber; 19 | 20 | @AWSIotDeviceProperty 21 | private Float threshold; 22 | 23 | @AWSIotDeviceProperty 24 | private Map sensors; 25 | 26 | private final List notifiers = new ArrayList<>(); 27 | 28 | private boolean enableMonitoring; 29 | private Thread monitoringThread; 30 | 31 | public TestDevice(String thingName, String serialNumber, Float threshold, Map sensors) { 32 | super(thingName); 33 | this.serialNumber = serialNumber; 34 | this.threshold = threshold; 35 | this.sensors = new HashMap<>(sensors); 36 | this.threshold = Float.valueOf(0f); 37 | } 38 | 39 | public String getSerialNumber() { 40 | return serialNumber; 41 | } 42 | 43 | public void setSerialNumber(String serialNumber) { 44 | this.serialNumber = serialNumber; 45 | } 46 | 47 | public Float getThreshold() { 48 | return threshold; 49 | } 50 | 51 | public void setThreshold(Float threshold) { 52 | this.threshold = threshold; 53 | } 54 | 55 | public Map getSensors() { 56 | return new HashMap(sensors); 57 | } 58 | 59 | public void setSensors(Map sensors) { 60 | this.sensors = new HashMap(sensors); 61 | } 62 | 63 | public Float getSensorValue(String sensorName) { 64 | return sensors.get(sensorName); 65 | } 66 | 67 | public void setSensorValue(String sensorName, Float sensorValue) { 68 | sensors.put(sensorName, sensorValue); 69 | } 70 | 71 | public Thread startMonitoring() { 72 | if (monitoringThread != null) { 73 | return monitoringThread; 74 | } 75 | 76 | enableMonitoring = true; 77 | monitoringThread = new Thread(new Runnable() { 78 | @Override 79 | public void run() { 80 | monitoringThread(); 81 | } 82 | }); 83 | 84 | monitoringThread.start(); 85 | return monitoringThread; 86 | } 87 | 88 | public void stopMonitoring() { 89 | if (monitoringThread != null) { 90 | enableMonitoring = false; 91 | try { 92 | monitoringThread.join(); 93 | } catch (InterruptedException e) { 94 | LOGGER.warning("joining monitoring thread got interrupted"); 95 | } 96 | monitoringThread = null; 97 | } 98 | } 99 | 100 | public void addNotifier(TestDeviceNotifier notifier) { 101 | notifiers.add(notifier); 102 | } 103 | 104 | public void removeNotifier(TestDeviceNotifier notifier) { 105 | notifiers.remove(notifier); 106 | } 107 | 108 | private void monitoringThread() { 109 | while (enableMonitoring) { 110 | for (Entry entry : sensors.entrySet()) { 111 | if (entry.getValue().compareTo(threshold) > 0) { 112 | LOGGER.finer("sensor " + entry.getKey() + " exceeded threshould (" + threshold + "): " 113 | + entry.getValue()); 114 | 115 | for (TestDeviceNotifier notifier : notifiers) { 116 | notifier.reportAlarm(entry.getKey(), entry.getValue(), threshold); 117 | } 118 | } 119 | } 120 | 121 | try { 122 | Thread.sleep(150); 123 | } catch (InterruptedException e) { 124 | LOGGER.warning("monitoring thread got interrupted"); 125 | break; 126 | } 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/TestDeviceNotifier.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client; 2 | 3 | public interface TestDeviceNotifier { 4 | 5 | void reportAlarm(String sensorName, Float sensorValue, Float threshold); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/TestTopic.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client; 2 | 3 | import java.util.Arrays; 4 | import java.util.logging.Logger; 5 | 6 | public class TestTopic extends AWSIotTopic { 7 | 8 | private static final Logger LOGGER = Logger.getLogger(TestTopic.class.getName()); 9 | 10 | public boolean isSuccess; 11 | public boolean isFailure; 12 | public boolean isTimeout; 13 | public long expectedMessageCount; 14 | public long unexpectedMessageCount; 15 | public byte[] lastPayload; 16 | 17 | public final byte[] expected; 18 | 19 | public TestTopic(String topic, byte[] expected) { 20 | super(topic); 21 | this.expected = expected; 22 | } 23 | 24 | @Override 25 | public void onMessage(AWSIotMessage message) { 26 | LOGGER.finer("message received for " + topic); 27 | lastPayload = message.getPayload(); 28 | if (Arrays.equals(expected, lastPayload)) { 29 | expectedMessageCount++; 30 | } else { 31 | unexpectedMessageCount++; 32 | } 33 | } 34 | 35 | @Override 36 | public void onSuccess() { 37 | LOGGER.finer("request success for " + topic); 38 | isSuccess = true; 39 | } 40 | 41 | @Override 42 | public void onFailure() { 43 | LOGGER.finer("request failure for " + topic); 44 | isFailure = true; 45 | } 46 | 47 | @Override 48 | public void onTimeout() { 49 | LOGGER.finer("request timeout for " + topic); 50 | isTimeout = true; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/auth: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.auth; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import com.amazonaws.auth.AWSCredentials; 6 | import com.amazonaws.auth.AWSCredentialsProvider; 7 | import com.amazonaws.auth.AWSSessionCredentials; 8 | import com.amazonaws.services.iot.client.auth.Credentials; 9 | import com.amazonaws.services.iot.client.auth.CredentialsProvider; 10 | import org.junit.Test; 11 | 12 | public class AwsCredentialsProviderAdapterTest { 13 | 14 | private static String ACCESS_KEY_ID = "TestAccessKeyId"; 15 | private static String SECRET_ACCESS_KEY = "TestSecretAccessKey"; 16 | private static String SESSION_TOKEN = "TestSessionToken"; 17 | 18 | private class TestAWSCredentials implements AWSCredentials { 19 | private String accessKeyId; 20 | private String secretAccessKey; 21 | 22 | public TestAWSCredentials(String accessKeyId, String secretAccessKey) { 23 | this.accessKeyId = accessKeyId; 24 | this.secretAccessKey = secretAccessKey; 25 | } 26 | 27 | public String getAWSAccessKeyId() { 28 | return accessKeyId; 29 | } 30 | 31 | public String getAWSSecretKey() { 32 | return secretAccessKey; 33 | } 34 | } 35 | 36 | private class TestSessionAWSCredentials extends TestAWSCredentials implements AWSSessionCredentials { 37 | private String sessionToken; 38 | 39 | public TestSessionAWSCredentials(String accessKeyId, String secretAccessKey, String sessionToken) { 40 | super(accessKeyId, secretAccessKey); 41 | this.sessionToken = sessionToken; 42 | } 43 | 44 | public String getSessionToken() { 45 | return sessionToken; 46 | } 47 | } 48 | 49 | private class TestStaticAWSCredentialsProvider implements AWSCredentialsProvider { 50 | 51 | private AWSCredentials credentials; 52 | 53 | public TestStaticAWSCredentialsProvider(AWSCredentials credentials) { 54 | this.credentials = credentials; 55 | } 56 | 57 | public AWSCredentials getCredentials() { 58 | return credentials; 59 | } 60 | 61 | public void refresh() {} 62 | } 63 | 64 | private void testAdapter(String accessKeyId, String secretAccessKey, String sessionToken) { 65 | AWSCredentials innerCreds = null; 66 | if (sessionToken == null) { 67 | innerCreds = new TestAWSCredentials(accessKeyId, secretAccessKey); 68 | } else { 69 | innerCreds = new TestSessionAWSCredentials(accessKeyId, secretAccessKey, sessionToken); 70 | } 71 | 72 | AWSCredentialsProvider innerProvider = new TestStaticAWSCredentialsProvider(innerCreds); 73 | CredentialsProvider provider = new AwsCredentialsProviderAdapter(innerProvider); 74 | 75 | Credentials credentials = provider.getCredentials(); 76 | assertEquals(accessKeyId, credentials.getAccessKeyId()); 77 | assertEquals(secretAccessKey, credentials.getSecretAccessKey()); 78 | assertEquals(sessionToken, credentials.getSessionToken()); 79 | } 80 | 81 | @Test 82 | public void testAdapterFetchCredentials() { 83 | testAdapter(ACCESS_KEY_ID, SECRET_ACCESS_KEY, null); 84 | } 85 | 86 | @Test 87 | public void testAdapterFetchSessionCredentials() { 88 | testAdapter(ACCESS_KEY_ID, SECRET_ACCESS_KEY, SESSION_TOKEN); 89 | } 90 | 91 | 92 | } 93 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/core/AwsIotCompletionTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.core; 2 | 3 | import java.util.concurrent.Executors; 4 | import java.util.concurrent.Future; 5 | import java.util.concurrent.ScheduledExecutorService; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.mockito.Mock; 12 | import org.mockito.invocation.InvocationOnMock; 13 | 14 | import static org.junit.Assert.*; 15 | import static org.mockito.Mockito.*; 16 | 17 | import org.mockito.runners.MockitoJUnitRunner; 18 | import org.mockito.stubbing.Answer; 19 | 20 | import com.amazonaws.services.iot.client.AWSIotException; 21 | import com.amazonaws.services.iot.client.AWSIotMessage; 22 | import com.amazonaws.services.iot.client.AWSIotQos; 23 | import com.amazonaws.services.iot.client.AWSIotTimeoutException; 24 | import com.amazonaws.services.iot.client.core.AbstractAwsIotClient; 25 | import com.amazonaws.services.iot.client.core.AwsIotCompletion; 26 | 27 | @RunWith(MockitoJUnitRunner.class) 28 | public class AwsIotCompletionTest { 29 | 30 | private static final String TEST_TOPIC = "test/topic"; 31 | private static final AWSIotQos TEST_QOS = AWSIotQos.QOS0; 32 | 33 | private final ScheduledExecutorService executionService = Executors.newScheduledThreadPool(2); 34 | 35 | @Mock 36 | private AbstractAwsIotClient client; 37 | 38 | @Before 39 | public void setup() { 40 | doAnswer(new Answer>() { 41 | @Override 42 | public Future answer(InvocationOnMock invocation) throws Throwable { 43 | Runnable runnable = (Runnable) invocation.getArguments()[0]; 44 | long timeout = (long) invocation.getArguments()[1]; 45 | return scheduleTimeoutTask(runnable, timeout); 46 | } 47 | }).when(client).scheduleTimeoutTask(any(Runnable.class), anyLong()); 48 | } 49 | 50 | @Test 51 | public void testSyncWithoutTimeoutSuccess() throws AWSIotException, AWSIotTimeoutException { 52 | AwsIotCompletion completion = new AwsIotCompletion(TEST_TOPIC, TEST_QOS, 0); 53 | 54 | // schedule a delayed task to simulate the callback 55 | scheduleTimeoutTask(completion, "success", 100); 56 | 57 | completion.get(client); 58 | } 59 | 60 | @Test(expected = AWSIotException.class) 61 | public void testSyncWithoutTimeoutFailure() throws AWSIotException, AWSIotTimeoutException { 62 | AwsIotCompletion completion = new AwsIotCompletion(TEST_TOPIC, TEST_QOS, 0); 63 | 64 | // schedule a delayed task to simulate the callback 65 | scheduleTimeoutTask(completion, "failure", 100); 66 | 67 | completion.get(client); 68 | } 69 | 70 | @Test 71 | public void testSyncWithTimeoutSuccess() throws AWSIotException, AWSIotTimeoutException { 72 | AwsIotCompletion completion = new AwsIotCompletion(TEST_TOPIC, TEST_QOS, 100); 73 | 74 | // schedule a delayed task to simulate the callback 75 | scheduleTimeoutTask(completion, "success", 50); 76 | 77 | completion.get(client); 78 | 79 | assertTrue(completion.timeoutTask.isCancelled()); 80 | } 81 | 82 | @Test(expected = AWSIotException.class) 83 | public void testSyncWithTimeoutFailure() throws AWSIotException, AWSIotTimeoutException { 84 | AwsIotCompletion completion = new AwsIotCompletion(TEST_TOPIC, TEST_QOS, (String) null, 100); 85 | 86 | // schedule a delayed task to simulate the callback 87 | scheduleTimeoutTask(completion, "failure", 50); 88 | 89 | try { 90 | completion.get(client); 91 | } finally { 92 | assertTrue(completion.timeoutTask.isCancelled()); 93 | } 94 | } 95 | 96 | @Test(expected = AWSIotTimeoutException.class) 97 | public void testSyncWithTimeoutTimeout() throws AWSIotException, AWSIotTimeoutException { 98 | AwsIotCompletion completion = new AwsIotCompletion(TEST_TOPIC, TEST_QOS, (byte[]) null, 100); 99 | 100 | try { 101 | completion.get(client); 102 | } finally { 103 | assertTrue(completion.timeoutTask.isCancelled()); 104 | } 105 | } 106 | 107 | @Test 108 | public void testAsyncWithoutTimeoutSuccess() throws AWSIotException, AWSIotTimeoutException, InterruptedException { 109 | TestMessage request = new TestMessage(TEST_TOPIC, TEST_QOS); 110 | AwsIotCompletion completion = new AwsIotCompletion(request, 0, true); 111 | 112 | // schedule a delayed task to simulate the callback 113 | scheduleTimeoutTask(completion, "success", 100); 114 | 115 | completion.get(client); 116 | 117 | synchronized (request) { 118 | while (!request.isSuccess && !request.isFailure && !request.isTimeout) { 119 | request.wait(150); 120 | break; 121 | } 122 | } 123 | 124 | assertTrue(request.isSuccess); 125 | assertFalse(request.isFailure); 126 | assertFalse(request.isTimeout); 127 | } 128 | 129 | @Test 130 | public void testAsyncWithoutTimeoutFailure() throws AWSIotException, AWSIotTimeoutException, InterruptedException { 131 | TestMessage request = new TestMessage(TEST_TOPIC, TEST_QOS); 132 | AwsIotCompletion completion = new AwsIotCompletion(request, 0, true); 133 | 134 | // schedule a delayed task to simulate the callback 135 | scheduleTimeoutTask(completion, "failure", 100); 136 | 137 | completion.get(client); 138 | 139 | synchronized (request) { 140 | while (!request.isSuccess && !request.isFailure && !request.isTimeout) { 141 | request.wait(200); 142 | break; 143 | } 144 | } 145 | 146 | assertTrue(request.isFailure); 147 | assertFalse(request.isSuccess); 148 | assertFalse(request.isTimeout); 149 | } 150 | 151 | @Test 152 | public void testAsyncWithTimeoutSuccess() throws AWSIotException, AWSIotTimeoutException, InterruptedException { 153 | TestMessage request = new TestMessage(TEST_TOPIC, TEST_QOS); 154 | AwsIotCompletion completion = new AwsIotCompletion(request, 100, true); 155 | 156 | // schedule a delayed task to simulate the callback 157 | scheduleTimeoutTask(completion, "success", 50); 158 | 159 | completion.get(client); 160 | 161 | synchronized (request) { 162 | while (!request.isSuccess && !request.isFailure && !request.isTimeout) { 163 | request.wait(200); 164 | break; 165 | } 166 | } 167 | 168 | assertTrue(request.isSuccess); 169 | assertFalse(request.isFailure); 170 | assertFalse(request.isTimeout); 171 | assertTrue(completion.timeoutTask.isCancelled()); 172 | } 173 | 174 | @Test 175 | public void testAsyncWithTimeoutFailure() throws AWSIotException, AWSIotTimeoutException, InterruptedException { 176 | TestMessage request = new TestMessage(TEST_TOPIC, TEST_QOS); 177 | AwsIotCompletion completion = new AwsIotCompletion(request, 100, true); 178 | 179 | // schedule a delayed task to simulate the callback 180 | scheduleTimeoutTask(completion, "failure", 50); 181 | 182 | completion.get(client); 183 | 184 | synchronized (request) { 185 | while (!request.isSuccess && !request.isFailure && !request.isTimeout) { 186 | request.wait(200); 187 | break; 188 | } 189 | } 190 | 191 | assertTrue(request.isFailure); 192 | assertFalse(request.isSuccess); 193 | assertFalse(request.isTimeout); 194 | assertTrue(completion.timeoutTask.isCancelled()); 195 | } 196 | 197 | @Test 198 | public void testAsyncWithTimeoutTimeout() throws AWSIotException, AWSIotTimeoutException, InterruptedException { 199 | TestMessage request = new TestMessage(TEST_TOPIC, TEST_QOS); 200 | AwsIotCompletion completion = new AwsIotCompletion(request, 100, true); 201 | 202 | completion.get(client); 203 | 204 | synchronized (request) { 205 | while (!request.isSuccess && !request.isFailure && !request.isTimeout) { 206 | request.wait(200); 207 | break; 208 | } 209 | } 210 | 211 | assertTrue(request.isTimeout); 212 | assertFalse(request.isSuccess); 213 | assertFalse(request.isFailure); 214 | assertTrue(completion.timeoutTask.isCancelled()); 215 | } 216 | 217 | class TestMessage extends AWSIotMessage { 218 | public boolean isSuccess; 219 | public boolean isFailure; 220 | public boolean isTimeout; 221 | 222 | public TestMessage(String topic, AWSIotQos qos) { 223 | super(topic, qos); 224 | } 225 | 226 | @Override 227 | public void onSuccess() { 228 | synchronized (this) { 229 | isSuccess = true; 230 | notify(); 231 | } 232 | } 233 | 234 | @Override 235 | public void onFailure() { 236 | synchronized (this) { 237 | isFailure = true; 238 | notify(); 239 | } 240 | } 241 | 242 | @Override 243 | public void onTimeout() { 244 | synchronized (this) { 245 | isTimeout = true; 246 | notify(); 247 | } 248 | } 249 | } 250 | 251 | private Future scheduleTimeoutTask(Runnable runnable, long timeout) { 252 | return executionService.schedule(runnable, timeout, TimeUnit.MILLISECONDS); 253 | } 254 | 255 | private Future scheduleTimeoutTask(final AwsIotCompletion completion, final String whichCallback, long timeout) { 256 | return executionService.schedule(new Runnable() { 257 | @Override 258 | public void run() { 259 | if (whichCallback.equals("success")) { 260 | completion.onSuccess(); 261 | } else if (whichCallback.equals("failure")) { 262 | completion.onFailure(); 263 | } else if (whichCallback.equals("timeout")) { 264 | completion.onTimeout(); 265 | } 266 | } 267 | }, timeout, TimeUnit.MILLISECONDS); 268 | } 269 | 270 | } 271 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/core/AwsIotWebsocketConnectionTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.core; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.mockito.Mockito.when; 5 | 6 | import java.util.Set; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.mockito.Mock; 12 | import org.mockito.runners.MockitoJUnitRunner; 13 | 14 | import com.amazonaws.services.iot.client.AWSIotException; 15 | 16 | @RunWith(MockitoJUnitRunner.class) 17 | public class AwsIotWebsocketConnectionTest { 18 | 19 | private final String ClientId = "test"; 20 | private final String EndPoint = "iot.us-east-1.AMAZONAWS.COM"; 21 | private final String AccessKeyId = "123"; 22 | private final String SecretAccessKey = "456"; 23 | private final String NewAccessKeyId = "new123"; 24 | 25 | @Mock 26 | private AbstractAwsIotClient client; 27 | 28 | private AwsIotWebsocketConnection connection; 29 | 30 | @Before 31 | public void setup() throws AWSIotException { 32 | when(client.getClientEndpoint()).thenReturn(EndPoint); 33 | when(client.getClientId()).thenReturn(ClientId); 34 | 35 | connection = new AwsIotWebsocketConnection(client, AccessKeyId, SecretAccessKey); 36 | } 37 | 38 | @Test 39 | public void testGetServerUris() throws AWSIotException { 40 | Set uris = connection.getServerUris(); 41 | 42 | assertEquals(1, uris.size()); 43 | } 44 | 45 | @Test 46 | public void testUpdateCredentails() throws AWSIotException { 47 | Set uris1 = connection.getServerUris(); 48 | 49 | connection.updateCredentials(NewAccessKeyId, SecretAccessKey, null); 50 | Set uris2 = connection.getServerUris(); 51 | 52 | assertEquals(1, uris1.size()); 53 | assertEquals(1, uris2.size()); 54 | assertTrue(!uris1.equals(uris2)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/mqtt/AwsIotMqttClientListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.mqtt; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertTrue; 5 | import static org.mockito.Matchers.any; 6 | import static org.mockito.Mockito.doAnswer; 7 | import static org.mockito.Mockito.doNothing; 8 | import static org.mockito.Mockito.times; 9 | import static org.mockito.Mockito.verify; 10 | import static org.mockito.Mockito.when; 11 | 12 | import java.util.Arrays; 13 | import java.util.concurrent.Future; 14 | 15 | import org.eclipse.paho.client.mqttv3.MqttMessage; 16 | import org.junit.Before; 17 | import org.junit.Test; 18 | import org.junit.runner.RunWith; 19 | import org.mockito.ArgumentCaptor; 20 | import org.mockito.Mock; 21 | import org.mockito.invocation.InvocationOnMock; 22 | import org.mockito.runners.MockitoJUnitRunner; 23 | import org.mockito.stubbing.Answer; 24 | 25 | import com.amazonaws.services.iot.client.AWSIotMessage; 26 | import com.amazonaws.services.iot.client.AWSIotQos; 27 | import com.amazonaws.services.iot.client.core.AbstractAwsIotClient; 28 | 29 | @RunWith(MockitoJUnitRunner.class) 30 | public class AwsIotMqttClientListenerTest { 31 | 32 | private static final String TEST_TOPIC = "test/topic"; 33 | private static final byte[] TEST_PAYLOAD = "test payload".getBytes(); 34 | 35 | @Mock 36 | private AbstractAwsIotClient client; 37 | @Mock 38 | private AwsIotMqttConnection connection; 39 | 40 | @Before 41 | public void setup() { 42 | doAnswer(new Answer>() { 43 | @Override 44 | public Future answer(InvocationOnMock invocation) throws Throwable { 45 | Runnable runnable = (Runnable) invocation.getArguments()[0]; 46 | runnable.run(); 47 | return null; 48 | } 49 | }).when(client).scheduleTask(any(Runnable.class)); 50 | 51 | when(client.getConnection()).thenReturn(connection); 52 | } 53 | 54 | @Test 55 | public void testConnectionLost() { 56 | AwsIotMqttClientListener listener = new AwsIotMqttClientListener(client); 57 | 58 | listener.connectionLost(null); 59 | 60 | verify(connection, times(1)).onConnectionFailure(); 61 | } 62 | 63 | @Test 64 | public void testOnMessageArrived() throws Exception { 65 | AwsIotMqttClientListener listener = new AwsIotMqttClientListener(client); 66 | 67 | MqttMessage mqttMessage = new MqttMessage(); 68 | mqttMessage.setQos(0); 69 | mqttMessage.setPayload(TEST_PAYLOAD); 70 | 71 | ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(AWSIotMessage.class); 72 | doNothing().when(client).dispatch(messageCaptor.capture()); 73 | 74 | listener.messageArrived(TEST_TOPIC, mqttMessage); 75 | 76 | verify(client, times(1)).dispatch(any(AWSIotMessage.class)); 77 | assertTrue(Arrays.equals(TEST_PAYLOAD, messageCaptor.getValue().getPayload())); 78 | assertEquals(AWSIotQos.QOS0, messageCaptor.getValue().getQos()); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/mqtt/AwsIotMqttConnectionListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.mqtt; 2 | 3 | import static org.mockito.Matchers.any; 4 | import static org.mockito.Mockito.doAnswer; 5 | import static org.mockito.Mockito.times; 6 | import static org.mockito.Mockito.verify; 7 | import static org.mockito.Mockito.when; 8 | 9 | import java.util.concurrent.Future; 10 | 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.mockito.Mock; 15 | import org.mockito.invocation.InvocationOnMock; 16 | import org.mockito.runners.MockitoJUnitRunner; 17 | import org.mockito.stubbing.Answer; 18 | 19 | import com.amazonaws.services.iot.client.core.AbstractAwsIotClient; 20 | import com.amazonaws.services.iot.client.core.AwsIotMessageCallback; 21 | 22 | @RunWith(MockitoJUnitRunner.class) 23 | public class AwsIotMqttConnectionListenerTest { 24 | 25 | @Mock 26 | private AbstractAwsIotClient client; 27 | @Mock 28 | private AwsIotMqttConnection connection; 29 | @Mock 30 | AwsIotMessageCallback userCallback; 31 | 32 | @Before 33 | public void setup() { 34 | doAnswer(new Answer>() { 35 | @Override 36 | public Future answer(InvocationOnMock invocation) throws Throwable { 37 | Runnable runnable = (Runnable) invocation.getArguments()[0]; 38 | runnable.run(); 39 | return null; 40 | } 41 | }).when(client).scheduleTask(any(Runnable.class)); 42 | 43 | when(client.getConnection()).thenReturn(connection); 44 | } 45 | 46 | @Test 47 | public void testOnConnectSuccess() { 48 | AwsIotMqttConnectionListener listener = new AwsIotMqttConnectionListener(client, true, userCallback); 49 | 50 | listener.onSuccess(null); 51 | 52 | verify(connection, times(1)).onConnectionSuccess(); 53 | verify(userCallback, times(1)).onSuccess(); 54 | } 55 | 56 | @Test 57 | public void testOnConnectFailure() { 58 | AwsIotMqttConnectionListener listener = new AwsIotMqttConnectionListener(client, true, userCallback); 59 | 60 | listener.onFailure(null, null); 61 | 62 | verify(connection, times(1)).onConnectionFailure(); 63 | verify(userCallback, times(1)).onFailure(); 64 | } 65 | 66 | @Test 67 | public void testOnDisconnectSuccess() { 68 | AwsIotMqttConnectionListener listener = new AwsIotMqttConnectionListener(client, false, userCallback); 69 | 70 | listener.onSuccess(null); 71 | 72 | verify(connection, times(1)).onConnectionClosed(); 73 | verify(userCallback, times(1)).onSuccess(); 74 | } 75 | 76 | @Test 77 | public void testOnDisconnectFailure() { 78 | AwsIotMqttConnectionListener listener = new AwsIotMqttConnectionListener(client, false, userCallback); 79 | 80 | listener.onFailure(null, null); 81 | 82 | verify(connection, times(1)).onConnectionClosed(); 83 | verify(userCallback, times(1)).onFailure(); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/mqtt/AwsIotMqttMessageListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.mqtt; 2 | 3 | import static org.mockito.Matchers.any; 4 | import static org.mockito.Mockito.doAnswer; 5 | import static org.mockito.Mockito.times; 6 | import static org.mockito.Mockito.verify; 7 | import static org.mockito.Mockito.when; 8 | 9 | import java.util.concurrent.Future; 10 | 11 | import org.eclipse.paho.client.mqttv3.MqttToken; 12 | import org.eclipse.paho.client.mqttv3.internal.wire.MqttSuback; 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.mockito.Mock; 17 | import org.mockito.invocation.InvocationOnMock; 18 | import org.mockito.runners.MockitoJUnitRunner; 19 | import org.mockito.stubbing.Answer; 20 | 21 | import com.amazonaws.services.iot.client.AWSIotMessage; 22 | import com.amazonaws.services.iot.client.core.AbstractAwsIotClient; 23 | 24 | @RunWith(MockitoJUnitRunner.class) 25 | public class AwsIotMqttMessageListenerTest { 26 | 27 | @Mock 28 | private AbstractAwsIotClient client; 29 | @Mock 30 | private AWSIotMessage message; 31 | @Mock 32 | private MqttToken token; 33 | @Mock 34 | private MqttSuback subAck; 35 | 36 | @Before 37 | public void setup() { 38 | doAnswer(new Answer>() { 39 | @Override 40 | public Future answer(InvocationOnMock invocation) throws Throwable { 41 | Runnable runnable = (Runnable) invocation.getArguments()[0]; 42 | runnable.run(); 43 | return null; 44 | } 45 | }).when(client).scheduleTask(any(Runnable.class)); 46 | 47 | when(token.getUserContext()).thenReturn(message); 48 | } 49 | 50 | @Test 51 | public void testOnSuccess() { 52 | AwsIotMqttMessageListener listener = new AwsIotMqttMessageListener(client); 53 | listener.onSuccess(token); 54 | 55 | verify(message, times(1)).onSuccess(); 56 | } 57 | 58 | @Test 59 | public void testOnSuccessWithSubAckAccepted() { 60 | AwsIotMqttMessageListener listener = new AwsIotMqttMessageListener(client); 61 | 62 | when(token.getResponse()).thenReturn(subAck); 63 | when(subAck.getGrantedQos()).thenReturn(new int[] { 1 }); 64 | 65 | listener.onSuccess(token); 66 | 67 | verify(message, times(1)).onSuccess(); 68 | } 69 | 70 | @Test 71 | public void testOnSuccessWithSubAckRejected() { 72 | AwsIotMqttMessageListener listener = new AwsIotMqttMessageListener(client); 73 | 74 | when(token.getResponse()).thenReturn(subAck); 75 | when(subAck.getGrantedQos()).thenReturn(new int[] { 128 }); 76 | 77 | listener.onSuccess(token); 78 | 79 | verify(message, times(1)).onFailure(); 80 | } 81 | 82 | @Test 83 | public void testOnFailure() { 84 | AwsIotMqttMessageListener listener = new AwsIotMqttMessageListener(client); 85 | listener.onFailure(token, null); 86 | 87 | verify(message, times(1)).onFailure(); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/shadow/AwsIotDeviceCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.shadow; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.mockito.Mockito.*; 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.mockito.Mock; 10 | import org.mockito.runners.MockitoJUnitRunner; 11 | 12 | import com.amazonaws.services.iot.client.AWSIotException; 13 | import com.amazonaws.services.iot.client.AWSIotMessage; 14 | import com.amazonaws.services.iot.client.AWSIotQos; 15 | import com.amazonaws.services.iot.client.AWSIotTimeoutException; 16 | import com.amazonaws.services.iot.client.core.AbstractAwsIotClient; 17 | import com.amazonaws.services.iot.client.shadow.AwsIotDeviceCommandManager.Command; 18 | 19 | @RunWith(MockitoJUnitRunner.class) 20 | public class AwsIotDeviceCommandTest { 21 | 22 | @Mock 23 | private AwsIotDeviceCommandManager commandManager; 24 | @Mock 25 | private AbstractAwsIotClient client; 26 | @Mock 27 | private AbstractAwsIotDevice device; 28 | @Mock 29 | private AWSIotMessage request; 30 | 31 | private AWSIotMessage response; 32 | 33 | @Before 34 | public void setup() { 35 | when(device.getClient()).thenReturn(client); 36 | 37 | response = new AWSIotMessage("test/topic", AWSIotQos.QOS0, "response payload"); 38 | } 39 | 40 | @Test 41 | public void testPutWhenDeviceReady() throws AWSIotException { 42 | AwsIotDeviceCommand command = new AwsIotDeviceCommand(commandManager, Command.GET, "1", request, 0, true); 43 | 44 | when(device.isCommandReady(Command.GET)).thenReturn(true); 45 | 46 | command.put(device); 47 | 48 | verify(client, times(1)).publish(command, 0); 49 | } 50 | 51 | @Test 52 | public void testPutWhenDeviceNotReady() throws AWSIotException { 53 | AwsIotDeviceCommand command = new AwsIotDeviceCommand(commandManager, Command.GET, "1", request, 0, true); 54 | 55 | when(device.isCommandReady(Command.GET)).thenReturn(false); 56 | 57 | command.put(device); 58 | 59 | verify(client, times(0)).publish(command, 0); 60 | } 61 | 62 | @Test 63 | public void testGetWithPayload() throws AWSIotException, AWSIotTimeoutException { 64 | AwsIotDeviceCommand command = new AwsIotDeviceCommand(commandManager, Command.GET, "1", request, 0, true); 65 | command.setResponse(response); 66 | command.onSuccess(); 67 | 68 | String payload = command.get(device); 69 | 70 | assertEquals("response payload", payload); 71 | } 72 | 73 | @Test 74 | public void testGetWithoutPayload() throws AWSIotException, AWSIotTimeoutException { 75 | AwsIotDeviceCommand command = new AwsIotDeviceCommand(commandManager, Command.GET, "1", request, 0, true); 76 | command.onSuccess(); 77 | 78 | String payload = command.get(device); 79 | 80 | assertEquals(null, payload); 81 | verify(request, times(0)).onSuccess(); 82 | } 83 | 84 | @Test 85 | public void testGetFailure() throws AWSIotException, AWSIotTimeoutException { 86 | AwsIotDeviceCommand command = new AwsIotDeviceCommand(commandManager, Command.GET, "1", request, 0, true); 87 | command.onFailure(); 88 | 89 | command.get(device); 90 | 91 | verify(request, times(1)).onFailure(); 92 | } 93 | 94 | @Test 95 | public void testGetTimeout() throws AWSIotException, AWSIotTimeoutException { 96 | AwsIotDeviceCommand command = new AwsIotDeviceCommand(commandManager, Command.GET, "1", request, 0, true); 97 | command.onTimeout(); 98 | 99 | command.get(device); 100 | 101 | verify(request, times(1)).onTimeout(); 102 | } 103 | 104 | @Test(expected = AWSIotException.class) 105 | public void testGetFailureSync() throws AWSIotException, AWSIotTimeoutException { 106 | AwsIotDeviceCommand command = new AwsIotDeviceCommand(commandManager, Command.GET, "1", request, 0, false); 107 | command.onFailure(); 108 | 109 | command.get(device); 110 | } 111 | 112 | @Test(expected = AWSIotTimeoutException.class) 113 | public void testGetTimeoutSync() throws AWSIotException, AWSIotTimeoutException { 114 | AwsIotDeviceCommand command = new AwsIotDeviceCommand(commandManager, Command.GET, "1", request, 0, false); 115 | command.onTimeout(); 116 | 117 | try { 118 | command.get(device); 119 | } finally{ 120 | verify(commandManager, times(1)).onCommandTimeout(command); 121 | } 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/shadow/AwsIotDeviceDeltaListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.shadow; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.mockito.Matchers.anyString; 5 | import static org.mockito.Mockito.never; 6 | import static org.mockito.Mockito.times; 7 | import static org.mockito.Mockito.verify; 8 | import static org.mockito.Mockito.when; 9 | 10 | import java.io.IOException; 11 | import java.util.concurrent.atomic.AtomicLong; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.mockito.Mock; 17 | import org.mockito.runners.MockitoJUnitRunner; 18 | 19 | import com.amazonaws.services.iot.client.AWSIotMessage; 20 | import com.amazonaws.services.iot.client.AWSIotQos; 21 | import com.fasterxml.jackson.core.JsonProcessingException; 22 | import com.fasterxml.jackson.databind.ObjectMapper; 23 | 24 | @RunWith(MockitoJUnitRunner.class) 25 | public class AwsIotDeviceDeltaListenerTest { 26 | 27 | private static final String TEST_SHADOW = "shadow"; 28 | private static final String TEST_TOPIC = "test/topic"; 29 | private static final AWSIotQos TEST_QOS = AWSIotQos.QOS0; 30 | 31 | @Mock 32 | private AbstractAwsIotDevice device; 33 | 34 | private ObjectMapper objectMapper; 35 | 36 | @Before 37 | public void setup() { 38 | objectMapper = new ObjectMapper(); 39 | device.enableVersioning = false; 40 | when(device.getThingName()).thenReturn(TEST_SHADOW); 41 | } 42 | 43 | @Test 44 | public void testNullPayload() { 45 | AWSIotMessage message = new AWSIotMessage(TEST_TOPIC, TEST_QOS); 46 | 47 | AwsIotDeviceDeltaListener listener = new AwsIotDeviceDeltaListener(TEST_TOPIC, TEST_QOS, device); 48 | listener.onMessage(message); 49 | 50 | verify(device, never()).getJsonObjectMapper(); 51 | } 52 | 53 | @Test 54 | public void testReadTreeNonObject() throws JsonProcessingException, IOException { 55 | when(device.getJsonObjectMapper()).thenReturn(objectMapper); 56 | 57 | AWSIotMessage message = new AWSIotMessage(TEST_TOPIC, TEST_QOS, "123"); 58 | 59 | AwsIotDeviceDeltaListener listener = new AwsIotDeviceDeltaListener(TEST_TOPIC, TEST_QOS, device); 60 | listener.onMessage(message); 61 | 62 | verify(device, times(1)).getJsonObjectMapper(); 63 | verify(device, never()).onShadowUpdate(anyString()); 64 | } 65 | 66 | @Test 67 | public void testReadTreeMissingState() throws JsonProcessingException, IOException { 68 | when(device.getJsonObjectMapper()).thenReturn(objectMapper); 69 | 70 | AWSIotMessage message = new AWSIotMessage(TEST_TOPIC, TEST_QOS, "{}"); 71 | 72 | AwsIotDeviceDeltaListener listener = new AwsIotDeviceDeltaListener(TEST_TOPIC, TEST_QOS, device); 73 | listener.onMessage(message); 74 | 75 | verify(device, times(1)).getJsonObjectMapper(); 76 | verify(device, never()).onShadowUpdate(anyString()); 77 | } 78 | 79 | @Test 80 | public void testOnShadowUpdate() throws JsonProcessingException, IOException { 81 | when(device.getJsonObjectMapper()).thenReturn(objectMapper); 82 | 83 | AWSIotMessage message = new AWSIotMessage(TEST_TOPIC, TEST_QOS, "{\"state\":{}}"); 84 | 85 | AwsIotDeviceDeltaListener listener = new AwsIotDeviceDeltaListener(TEST_TOPIC, TEST_QOS, device); 86 | listener.onMessage(message); 87 | 88 | verify(device, times(1)).getJsonObjectMapper(); 89 | verify(device, times(1)).onShadowUpdate(anyString()); 90 | } 91 | 92 | @Test 93 | public void testVersioningEnabledMissingVersion() throws JsonProcessingException, IOException { 94 | when(device.getJsonObjectMapper()).thenReturn(objectMapper); 95 | device.enableVersioning = true; 96 | 97 | AWSIotMessage message = new AWSIotMessage(TEST_TOPIC, TEST_QOS, "{\"state\":{}}"); 98 | 99 | AwsIotDeviceDeltaListener listener = new AwsIotDeviceDeltaListener(TEST_TOPIC, TEST_QOS, device); 100 | listener.onMessage(message); 101 | 102 | verify(device, times(1)).getJsonObjectMapper(); 103 | verify(device, never()).getLocalVersion(); 104 | } 105 | 106 | @Test 107 | public void testVersioningEnabledReceivedOldVersion() throws JsonProcessingException, IOException { 108 | when(device.getJsonObjectMapper()).thenReturn(objectMapper); 109 | when(device.getLocalVersion()).thenReturn(new AtomicLong(2)); 110 | device.enableVersioning = true; 111 | 112 | AWSIotMessage message = new AWSIotMessage(TEST_TOPIC, TEST_QOS, "{\"version\":1, \"state\":{}}"); 113 | 114 | AwsIotDeviceDeltaListener listener = new AwsIotDeviceDeltaListener(TEST_TOPIC, TEST_QOS, device); 115 | listener.onMessage(message); 116 | 117 | verify(device, times(1)).getJsonObjectMapper(); 118 | verify(device, never()).onShadowUpdate(anyString()); 119 | } 120 | 121 | @Test 122 | public void testVersioningEnabledReceivedNewerVersion() throws JsonProcessingException, IOException { 123 | AtomicLong localVersion = new AtomicLong(2); 124 | when(device.getJsonObjectMapper()).thenReturn(objectMapper); 125 | when(device.getLocalVersion()).thenReturn(localVersion); 126 | device.enableVersioning = true; 127 | 128 | AWSIotMessage message = new AWSIotMessage(TEST_TOPIC, TEST_QOS, "{\"version\":3, \"state\":{}}"); 129 | 130 | AwsIotDeviceDeltaListener listener = new AwsIotDeviceDeltaListener(TEST_TOPIC, TEST_QOS, device); 131 | listener.onMessage(message); 132 | 133 | assertEquals(3, localVersion.get()); 134 | verify(device, times(1)).getJsonObjectMapper(); 135 | verify(device, times(1)).onShadowUpdate(anyString()); 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/shadow/AwsIotDeviceReportMessageTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.shadow; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.mockito.Mockito.never; 5 | import static org.mockito.Mockito.times; 6 | import static org.mockito.Mockito.verify; 7 | import static org.mockito.Mockito.when; 8 | 9 | import java.util.concurrent.atomic.AtomicLong; 10 | 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.mockito.Mock; 14 | import org.mockito.runners.MockitoJUnitRunner; 15 | 16 | import com.amazonaws.services.iot.client.AWSIotDeviceErrorCode; 17 | import com.amazonaws.services.iot.client.AWSIotQos; 18 | 19 | @RunWith(MockitoJUnitRunner.class) 20 | public class AwsIotDeviceReportMessageTest { 21 | 22 | private static final String TEST_TOPIC = "test/topic"; 23 | private static final AWSIotQos TEST_QOS = AWSIotQos.QOS0; 24 | 25 | @Mock 26 | private AbstractAwsIotDevice device; 27 | 28 | @Test 29 | public void testOnSuccessLocalVersionUnchanged() { 30 | AtomicLong localVersion = new AtomicLong(2); 31 | when(device.getLocalVersion()).thenReturn(localVersion); 32 | 33 | long reportVersion = 2; 34 | AwsIotDeviceReportMessage message = new AwsIotDeviceReportMessage(TEST_TOPIC, TEST_QOS, reportVersion, "", 35 | device); 36 | message.onSuccess(); 37 | 38 | assertEquals(3, localVersion.get()); 39 | } 40 | 41 | @Test 42 | public void testOnSuccessLocalVersionChanged() { 43 | AtomicLong localVersion = new AtomicLong(4); 44 | when(device.getLocalVersion()).thenReturn(localVersion); 45 | 46 | long reportVersion = 2; 47 | AwsIotDeviceReportMessage message = new AwsIotDeviceReportMessage(TEST_TOPIC, TEST_QOS, reportVersion, "", 48 | device); 49 | message.onSuccess(); 50 | 51 | assertEquals(4, localVersion.get()); 52 | } 53 | 54 | @Test 55 | public void testOnFailureVersionConflict() { 56 | AwsIotDeviceReportMessage message = new AwsIotDeviceReportMessage(TEST_TOPIC, TEST_QOS, 1, "", device); 57 | message.setErrorCode(AWSIotDeviceErrorCode.CONFLICT); 58 | 59 | message.onFailure(); 60 | 61 | verify(device, times(1)).startVersionSync(); 62 | } 63 | 64 | @Test 65 | public void testOnFailureNonVersionConflict() { 66 | AwsIotDeviceReportMessage message = new AwsIotDeviceReportMessage(TEST_TOPIC, TEST_QOS, 1, "", device); 67 | message.setErrorCode(AWSIotDeviceErrorCode.NOT_FOUND); 68 | 69 | message.onFailure(); 70 | 71 | verify(device, never()).startVersionSync(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/shadow/AwsIotDeviceSyncMessageTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.shadow; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.mockito.Mockito.never; 5 | import static org.mockito.Mockito.verify; 6 | import static org.mockito.Mockito.when; 7 | import static org.mockito.Mockito.lenient; 8 | 9 | import java.util.concurrent.atomic.AtomicLong; 10 | 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.mockito.Mock; 15 | import org.mockito.runners.MockitoJUnitRunner; 16 | 17 | import com.amazonaws.services.iot.client.AWSIotDeviceErrorCode; 18 | import com.amazonaws.services.iot.client.AWSIotQos; 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | 21 | @RunWith(MockitoJUnitRunner.class) 22 | public class AwsIotDeviceSyncMessageTest { 23 | 24 | private static final String TEST_TOPIC = "test/topic"; 25 | private static final AWSIotQos TEST_QOS = AWSIotQos.QOS0; 26 | 27 | @Mock 28 | private AbstractAwsIotDevice device; 29 | 30 | private ObjectMapper objectMapper; 31 | 32 | @Before 33 | public void setup() { 34 | objectMapper = new ObjectMapper(); 35 | when(device.getJsonObjectMapper()).thenReturn(objectMapper); 36 | 37 | } 38 | 39 | @Test 40 | public void testOnSuccessInvalidPayload() { 41 | AwsIotDeviceSyncMessage message = new AwsIotDeviceSyncMessage(TEST_TOPIC, TEST_QOS, device); 42 | message.setStringPayload("123"); 43 | 44 | message.onSuccess(); 45 | verify(device, never()).getLocalVersion(); 46 | } 47 | 48 | @Test 49 | public void testOnSuccessVersionAlreadyUpdated() { 50 | AtomicLong localVersion = new AtomicLong(2); 51 | when(device.getLocalVersion()).thenReturn(localVersion); 52 | 53 | AwsIotDeviceSyncMessage message = new AwsIotDeviceSyncMessage(TEST_TOPIC, TEST_QOS, device); 54 | message.setStringPayload("{\"version\":1}"); 55 | 56 | message.onSuccess(); 57 | 58 | assertEquals(2, localVersion.get()); 59 | } 60 | 61 | @Test 62 | public void testOnSuccessVersionNotUpdated() { 63 | AtomicLong localVersion = new AtomicLong(-1); 64 | when(device.getLocalVersion()).thenReturn(localVersion); 65 | 66 | AwsIotDeviceSyncMessage message = new AwsIotDeviceSyncMessage(TEST_TOPIC, TEST_QOS, device); 67 | message.setStringPayload("{\"version\":1}"); 68 | 69 | message.onSuccess(); 70 | 71 | assertEquals(1, localVersion.get()); 72 | } 73 | 74 | @Test 75 | public void testOnFailureDeviceNotFound() { 76 | AtomicLong localVersion = new AtomicLong(-1); 77 | when(device.getLocalVersion()).thenReturn(localVersion); 78 | 79 | AwsIotDeviceSyncMessage message = new AwsIotDeviceSyncMessage(TEST_TOPIC, TEST_QOS, device); 80 | message.setErrorCode(AWSIotDeviceErrorCode.NOT_FOUND); 81 | 82 | message.onFailure(); 83 | 84 | assertEquals(0, localVersion.get()); 85 | } 86 | 87 | @Test 88 | public void testOnFailureOtherError() { 89 | AtomicLong localVersion = new AtomicLong(-1); 90 | lenient().when(device.getLocalVersion()).thenReturn(localVersion); 91 | 92 | AwsIotDeviceSyncMessage message = new AwsIotDeviceSyncMessage(TEST_TOPIC, TEST_QOS, device); 93 | message.setErrorCode(AWSIotDeviceErrorCode.INTERNAL_SERVICE_FAILURE); 94 | 95 | message.onFailure(); 96 | 97 | assertEquals(-1, localVersion.get()); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/system_props_mutualAuth.properties: -------------------------------------------------------------------------------- 1 | clientEndpoint=ajje7lpljulm4-ats.iot.us-east-1.amazonaws.com 2 | clientId=DefaultClientId 3 | thingName=DefaultThingName 4 | privateMaterial=arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestPrivateKey-vNUQU8 5 | publicMaterial=arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestCertificate-vTRwjE 6 | isWebSocket=false 7 | authMode=CertificateMutualAuthentication 8 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/system_props_websocket.properties: -------------------------------------------------------------------------------- 1 | clientEndpoint=ajje7lpljulm4-ats.iot.us-east-1.amazonaws.com 2 | clientId=DefaultClientId 3 | thingName=DefaultThingName 4 | privateMaterial=arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestWebsocketSecretAccessKey-MKTSaV 5 | publicMaterial=arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestWebsocketAccessKeyId-1YdB9z 6 | isWebSocket=true 7 | authMode=MqttOverWebSocketSigV4Signing 8 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/util/AwsIotTlsSocketFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.util; 2 | 3 | import static org.mockito.Matchers.any; 4 | import static org.mockito.Matchers.anyBoolean; 5 | import static org.mockito.Matchers.anyInt; 6 | import static org.mockito.Matchers.anyString; 7 | import static org.mockito.Matchers.nullable; 8 | import static org.mockito.Mockito.times; 9 | import static org.mockito.Mockito.verify; 10 | import static org.mockito.Mockito.when; 11 | 12 | import java.io.IOException; 13 | import java.net.InetAddress; 14 | import java.net.Socket; 15 | import java.net.UnknownHostException; 16 | 17 | import javax.net.ssl.SSLSocket; 18 | import javax.net.ssl.SSLSocketFactory; 19 | 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | import org.junit.runner.RunWith; 23 | import org.mockito.Mock; 24 | import org.mockito.runners.MockitoJUnitRunner; 25 | 26 | @RunWith(MockitoJUnitRunner.class) 27 | public class AwsIotTlsSocketFactoryTest { 28 | 29 | @Mock 30 | private SSLSocketFactory sslSocketFactory; 31 | @Mock 32 | private SSLSocket socket; 33 | 34 | private AwsIotTlsSocketFactory tlsSocketFactory; 35 | 36 | @Before 37 | public void setup() { 38 | tlsSocketFactory = new AwsIotTlsSocketFactory(sslSocketFactory); 39 | } 40 | 41 | @Test 42 | public void getDefaultCipherSuites() { 43 | tlsSocketFactory.getDefaultCipherSuites(); 44 | 45 | verify(sslSocketFactory, times(1)).getDefaultCipherSuites(); 46 | } 47 | 48 | @Test 49 | public void getSupportedCipherSuites() { 50 | tlsSocketFactory.getSupportedCipherSuites(); 51 | 52 | verify(sslSocketFactory, times(1)).getSupportedCipherSuites(); 53 | } 54 | 55 | @Test 56 | public void testCreateSocket() throws IOException { 57 | when(sslSocketFactory.createSocket()).thenReturn(socket); 58 | 59 | tlsSocketFactory.createSocket(); 60 | 61 | verify(socket, times(1)).setEnabledProtocols(new String[] { "TLSv1.2" }); 62 | } 63 | 64 | @Test 65 | public void testCreateSocketWithSocket() throws IOException { 66 | when(sslSocketFactory.createSocket(nullable(Socket.class), anyString(), anyInt(), anyBoolean())).thenReturn(socket); 67 | 68 | tlsSocketFactory.createSocket(nullable(Socket.class), anyString(), anyInt(), anyBoolean()); 69 | 70 | verify(socket, times(1)).setEnabledProtocols(new String[] { "TLSv1.2" }); 71 | } 72 | 73 | @Test 74 | public void testCreateSocketWithHost() throws IOException, UnknownHostException { 75 | when(sslSocketFactory.createSocket(anyString(), anyInt())).thenReturn(socket); 76 | 77 | tlsSocketFactory.createSocket(anyString(), anyInt()); 78 | 79 | verify(socket, times(1)).setEnabledProtocols(new String[] { "TLSv1.2" }); 80 | } 81 | 82 | @Test 83 | public void testCreateSocketWithInetAddress() throws IOException, UnknownHostException { 84 | when(sslSocketFactory.createSocket(anyString(), anyInt(), nullable(InetAddress.class), anyInt())).thenReturn(socket); 85 | 86 | tlsSocketFactory.createSocket(anyString(), anyInt(), nullable(InetAddress.class), anyInt()); 87 | 88 | verify(socket, times(1)).setEnabledProtocols(new String[] { "TLSv1.2" }); 89 | } 90 | 91 | @Test 92 | public void testCreateSocketWithInetAddressAndPort() throws IOException { 93 | when(sslSocketFactory.createSocket(nullable(InetAddress.class), anyInt())).thenReturn(socket); 94 | 95 | tlsSocketFactory.createSocket(nullable(InetAddress.class), anyInt()); 96 | 97 | verify(socket, times(1)).setEnabledProtocols(new String[] { "TLSv1.2" }); 98 | } 99 | 100 | @Test 101 | public void testCreateSocketWithInetAddressAndLocalInetAddress() throws IOException { 102 | when(sslSocketFactory.createSocket(nullable(InetAddress.class), anyInt(), nullable(InetAddress.class), anyInt())) 103 | .thenReturn(socket); 104 | 105 | tlsSocketFactory.createSocket(nullable(InetAddress.class), anyInt(), nullable(InetAddress.class), anyInt()); 106 | 107 | verify(socket, times(1)).setEnabledProtocols(new String[] { "TLSv1.2" }); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /aws-iot-device-sdk-java/src/test/java/com/amazonaws/services/iot/client/util/AwsIotWebSocketUrlSignerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.services.iot.client.util; 2 | 3 | import com.amazonaws.services.iot.client.AWSIotException; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.runners.MockitoJUnitRunner; 7 | 8 | import java.util.Date; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | 12 | @RunWith(MockitoJUnitRunner.class) 13 | public class AwsIotWebSocketUrlSignerTest { 14 | 15 | private final String PrefixedEndPoint = "hostname.iot.us-east-1.AMAZONAWS.COM:443"; 16 | private final String EndPoint = "iot.us-east-1.AMAZONAWS.COM"; 17 | private final String AccessKeyId = "123"; 18 | private final String SecretAccessKey = "456"; 19 | private final String SessionToken = "abc"; 20 | private final Date SigningDate = new Date(1451606400000l); 21 | private final String PrefixedEndPointSigned = "wss://hostname.iot.us-east-1.amazonaws.com:443/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=123%2F20160101%2Fus-east-1%2Fiotdata%2Faws4_request&X-Amz-Date=20160101T000000Z&X-Amz-SignedHeaders=host&X-Amz-Signature=08b80c7273fa6c9d8bd815081c80e60818f2bf974213993a1cd4463a5785b1ce"; 22 | private final String EndPointSigned = "wss://iot.us-east-1.amazonaws.com/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=123%2F20160101%2Fus-east-1%2Fiotdata%2Faws4_request&X-Amz-Date=20160101T000000Z&X-Amz-SignedHeaders=host&X-Amz-Signature=b50019dd3ec2d316a6a7938f363f6c792b5f58c04e1e6535d6ae277bf8cf3304"; 23 | 24 | @Test 25 | public void testSigningPrefixEndpoint() throws AWSIotException { 26 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(PrefixedEndPoint, AccessKeyId, 27 | SecretAccessKey, null); 28 | 29 | String url = urlSigner.getSignedUrl(SigningDate); 30 | 31 | assertEquals(PrefixedEndPointSigned, url); 32 | } 33 | 34 | @Test 35 | public void testSigningRegularEndpoint() throws AWSIotException { 36 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(EndPoint, AccessKeyId, SecretAccessKey, null); 37 | 38 | String url = urlSigner.getSignedUrl(SigningDate); 39 | 40 | assertEquals(EndPointSigned, url); 41 | } 42 | 43 | @Test 44 | public void testSigningWithSessionToken() throws AWSIotException { 45 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(EndPoint, AccessKeyId, SecretAccessKey, 46 | SessionToken); 47 | 48 | String url = urlSigner.getSignedUrl(SigningDate); 49 | 50 | assertEquals(EndPointSigned + "&X-Amz-Security-Token=" + SessionToken, url); 51 | } 52 | 53 | @Test(expected = IllegalArgumentException.class) 54 | public void testSigningWithInvalidEndpoint() throws AWSIotException { 55 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner("hostname.iot.us-east-1.AMAZON.COM", 56 | AccessKeyId, SecretAccessKey, SessionToken); 57 | urlSigner.getSignedUrl(SigningDate); 58 | } 59 | 60 | @Test(expected = IllegalArgumentException.class) 61 | public void testSigningWithCredentials() throws AWSIotException { 62 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(EndPoint, null, null, SessionToken); 63 | urlSigner.getSignedUrl(SigningDate); 64 | } 65 | 66 | @Test(expected = IllegalArgumentException.class) 67 | public void testNullRegionWithCreds() { 68 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(EndPoint, null, null, SessionToken, null); 69 | } 70 | 71 | @Test(expected = IllegalArgumentException.class) 72 | public void testNullRegion() { 73 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(EndPoint, null); 74 | } 75 | 76 | public void testRegionDerivedFromEndpointWithCreds() { 77 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(EndPoint, null, null, SessionToken); 78 | assertEquals("us-east-1", urlSigner.getRegion()); 79 | } 80 | 81 | public void testRegionDerivedFromEndpoint() { 82 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(EndPoint); 83 | assertEquals("us-east-1", urlSigner.getRegion()); 84 | } 85 | 86 | public void testRegionSetFromTheConstructorWithCreds() { 87 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(EndPoint, null, null, SessionToken, "us" + 88 | "-east-2"); 89 | assertEquals("us-east-2", urlSigner.getRegion()); 90 | } 91 | 92 | public void testRegionSetFromTheConstructor() { 93 | AwsIotWebSocketUrlSigner urlSigner = new AwsIotWebSocketUrlSigner(EndPoint, "us-east-2"); 94 | assertEquals("us-east-2", urlSigner.getRegion()); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /codebuild/cd/promote-release.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | #this buildspec assumes the ubuntu 16.04:x64 image 3 | # This job is responsible for artifacting the JAR which will have all of the other shared libs stuffed 4 | # into it once all platforms are built and artifacted 5 | phases: 6 | install: 7 | commands: 8 | - sudo add-apt-repository ppa:openjdk-r/ppa 9 | - sudo apt-get update -y 10 | - sudo apt-get install openjdk-8-jdk-headless maven -y -f 11 | - sudo apt-get install jq -y 12 | # need latest awscli for secretsmanager 13 | - sudo pip3 install awscli --upgrade 14 | 15 | pre_build: 16 | commands: 17 | - cd $CODEBUILD_SRC_DIR/aws-iot-device-sdk-java 18 | - export PKG_VERSION=$(git describe --tags | cut -f2 -dv) 19 | - echo PKG_VERSION=$PKG_VERSION 20 | # Set version to PKG_VERSION 21 | - sed -i 's/0.0.1-dev/'"$PKG_VERSION"'/g' pom.xml 22 | - sed -i 's/0.0.1-dev/'"$PKG_VERSION"'/g' aws-iot-device-sdk-java/pom.xml 23 | - sed -i 's/0.0.1-dev/'"$PKG_VERSION"'/g' aws-iot-device-sdk-java-samples/pom.xml 24 | - sed -i 's/0.0.1-dev/'"$PKG_VERSION"'/g' aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/mqtt/AwsIotMqttConnection.java 25 | # Get java v1 gpg files 26 | - aws s3 cp --recursive s3://code-sharing-aws-crt/gpg-java-v1/ maven-gpg 27 | # manully copy the maven-gpg in subfolder, since codeBuild does not set localRepository correctly 28 | - cp -r maven-gpg aws-iot-device-sdk-java/maven-gpg 29 | - cp -r maven-gpg aws-iot-device-sdk-java-samples/maven-gpg 30 | # install settings.xml to ~/.m2/settings.xml 31 | - mkdir -p $HOME/.m2 32 | - aws s3 cp s3://code-sharing-aws-crt/iot-sdk-java-v1.settings.xml $HOME/.m2/settings.xml 33 | - aws --query "SecretString" secretsmanager get-secret-value --secret-id Sonatype/JIRA/token/V1 > sonatype_secret 34 | - jq fromjson sonatype_secret > sonatype_json 35 | - export ST_PASSWORD=$(jq -r '.password' sonatype_json) 36 | - export ESCAPED_PASSWORD=$(printf '%s\n' "$ST_PASSWORD" | sed 's:[\\/&]:\\&:g') 37 | - export ST_USERNAME=$(jq -r '.username' sonatype_json) 38 | - aws --query "SecretString" secretsmanager get-secret-value --secret-id gpg/IoT/JAVA/V1 > gpg_secret 39 | - jq fromjson gpg_secret > gpg_json 40 | - export GPG_PRINCIPAL=$(jq -r '.username' gpg_json) 41 | - export GPG_CREDENTIAL=$(jq -r '.password' gpg_json) 42 | # Use the password from secret manager to update the settings 43 | - sed -i 's/sonatype_Principal/'"$ST_USERNAME"'/g' $HOME/.m2/settings.xml 44 | - sed -i 's/sonatype_Credential/'"$ESCAPED_PASSWORD"'/g' $HOME/.m2/settings.xml 45 | - sed -i 's/gpg_Principal/'"$GPG_PRINCIPAL"'/g' $HOME/.m2/settings.xml 46 | - sed -i 's/gpg_Credential/'"$GPG_CREDENTIAL"'/g' $HOME/.m2/settings.xml 47 | 48 | 49 | build: 50 | commands: 51 | - cd $CODEBUILD_SRC_DIR/aws-iot-device-sdk-java 52 | # Trigger the release of the last staged package in the staging repository 53 | - mvn -s $HOME/.m2/settings.xml clean package -Dmaven.test.skip=true 54 | - mvn -s $HOME/.m2/settings.xml clean deploy -P publishing -e -X 55 | - mvn -s $HOME/.m2/settings.xml nexus-staging:release -e -X 56 | 57 | cache: 58 | paths: 59 | - "/root/.m2/**/*" 60 | -------------------------------------------------------------------------------- /codebuild/cd/test-version-exists.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | set -x 4 | # force a failure if there's no tag 5 | git describe --tags 6 | # now get the tag 7 | CURRENT_TAG=$(git describe --tags | cut -f2 -dv) 8 | # convert v0.2.12-2-g50254a9 to 0.2.12 9 | CURRENT_TAG_VERSION=$(git describe --tags | cut -f1 -d'-' | cut -f2 -dv) 10 | # if there's a hash on the tag, then this is not a release tagged commit 11 | if [ "$CURRENT_TAG" != "$CURRENT_TAG_VERSION" ]; then 12 | echo "Current tag version is not a release tag, cut a new release if you want to publish." 13 | exit 1 14 | fi 15 | 16 | PUBLISHED_TAG_VERSION=$(curl -s "https://repo.maven.apache.org/maven2/com/amazonaws/aws-iot-device-sdk-java/maven-metadata.xml" | grep "" | cut -f2 -d ">" | cut -f1 -d "<") 17 | if [ "$PUBLISHED_TAG_VERSION" == "$CURRENT_TAG_VERSION" ]; then 18 | echo "$CURRENT_TAG_VERSION is already in Sonatype, cut a new tag if you want to upload another version." 19 | exit 1 20 | fi 21 | 22 | echo "$CURRENT_TAG_VERSION currently does not exist in Sonatype, allowing pipeline to continue." 23 | exit 0 24 | -------------------------------------------------------------------------------- /codebuild/cd/test-version-exists.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | #this build spec assumes the ubuntu 16.04:x64 image 3 | #this build run simply verifies we haven't published something at this tag yet. 4 | #if we have we fail the build and stop the pipeline, if we haven't we allow the pipeline to run. 5 | phases: 6 | build: 7 | commands: 8 | - cd $CODEBUILD_SRC_DIR/aws-iot-device-sdk-java 9 | - bash ./codebuild/cd/test-version-exists.sh 10 | 11 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.amazonaws 4 | aws-iot-device-sdk-java-pom 5 | 0.0.1-dev 6 | pom 7 | AWS IoT Device SDK for Java 8 | The AWS IoT Device SDK for Java provides Java APIs for devices to connect to AWS IoT service using the MQTT protocol. The SDK also provides support for AWS IoT specific features, such as Thing Shadow and Thing Shadow abstraction. 9 | https://aws.amazon.com/iot/sdk 10 | 11 | 12 | Apache License, Version 2.0 13 | https://aws.amazon.com/apache2.0 14 | repo 15 | 16 | 17 | 18 | 19 | amazonwebservices 20 | Amazon Web Services 21 | https://aws.amazon.com 22 | 23 | developer 24 | 25 | 26 | 27 | 28 | https://github.com/aws/aws-iot-device-sdk-java.git 29 | 30 | 31 | aws-iot-device-sdk-java 32 | aws-iot-device-sdk-java-samples 33 | 34 | 35 | UTF-8 36 | 37 | 38 | 39 | ossrh 40 | https://aws.oss.sonatype.org/content/repositories/snapshots 41 | 42 | 43 | 44 | 45 | 46 | org.sonatype.plugins 47 | nexus-staging-maven-plugin 48 | 1.6.8 49 | true 50 | 51 | ossrh 52 | https://aws.oss.sonatype.org/ 53 | false 54 | 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-compiler-plugin 59 | 3.5.1 60 | 61 | 1.7 62 | 1.7 63 | 1.7 64 | 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-gpg-plugin 69 | 1.6 70 | 71 | 72 | sign-artifacts 73 | verify 74 | 75 | sign 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | --------------------------------------------------------------------------------