summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorC.J. Collier <cjcollier@linuxfoundation.org>2017-12-19 16:50:20 -0800
committerC.J. Collier <cjcollier@linuxfoundation.org>2017-12-19 16:54:52 -0800
commita85c59dbe486d7bf44c3a4e36808cc58f9a7ad90 (patch)
treed0b0cda7567e52e5a9782f86b558597701785ec9
parenta87c2ecea281db8e2b2e751770e2b4bcaa5fbce8 (diff)
Alexa code related to RT#50059
Source from https://github.com/intel/aws-iotivity All directories on master besides UpnpBridge included All code licensed under Apache 2.0 Change-Id: I8679fa5f1185947cc89c5a9d34c1be290fad182f Signed-off-by: C.J. Collier <cjcollier@linuxfoundation.org>
-rw-r--r--alexa-bridge-skill-lambda/LICENSE.md195
-rw-r--r--alexa-bridge-skill-lambda/README.md39
-rw-r--r--alexa-bridge-skill-lambda/index.js366
-rw-r--r--alexa-bridge-skill-lambda/intents.json161
-rw-r--r--alexa-iotivity-bridge-demo/LICENSE.md195
-rw-r--r--alexa-iotivity-bridge-demo/README.md39
-rwxr-xr-xalexa-iotivity-bridge-demo/build.sh10
-rw-r--r--alexa-iotivity-bridge-demo/options.txt2
-rwxr-xr-xalexa-iotivity-bridge-demo/run.sh3
-rwxr-xr-xalexa-iotivity-bridge-demo/runscanner.sh3
-rw-r--r--alexa-iotivity-bridge-demo/sourcefiles.txt23
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/CommandArguments.java90
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/PrivateKeyReader.java491
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/SampleUtil.java149
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/AlexaIotivityBridgeDemo.java186
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/BinarySwitch.java86
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Brightness.java86
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Configuration.java84
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/ConnectedThing.java163
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Device.java227
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityClient.java894
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityScanner.java123
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityScannerClient.java810
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Light.java177
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Link.java132
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Links.java93
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java115
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Resource.java101
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Service.java52
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/UpdateAcceptedTopicListener.java39
-rw-r--r--alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/UpdatePublisherListener.java48
-rw-r--r--alexa-smart-home-skill-lambda/LICENSE.md195
-rw-r--r--alexa-smart-home-skill-lambda/README.md28
-rw-r--r--alexa-smart-home-skill-lambda/index.js547
-rw-r--r--ocf-light-server/LICENSE.md195
-rw-r--r--ocf-light-server/README.md51
-rwxr-xr-xocf-light-server/build.sh12
-rw-r--r--ocf-light-server/options.txt2
-rw-r--r--ocf-light-server/res/bulb-icon-32x32.pngbin0 -> 1556 bytes
-rw-r--r--ocf-light-server/res/light-off.pngbin0 -> 36254 bytes
-rw-r--r--ocf-light-server/res/light-on.pngbin0 -> 40066 bytes
-rwxr-xr-xocf-light-server/run.sh1
-rw-r--r--ocf-light-server/sourcefiles.txt13
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/Brightness.java103
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/Light.java259
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/LightConfig.java86
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/LightImageObserver.java31
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/LightPanel.java213
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/Link.java90
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/Links.java82
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java115
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/OcfLightDevice.java203
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/Resource.java240
-rw-r--r--ocf-light-server/src/main/java/org/iotivity/base/examples/Switch.java97
54 files changed, 7745 insertions, 0 deletions
diff --git a/alexa-bridge-skill-lambda/LICENSE.md b/alexa-bridge-skill-lambda/LICENSE.md
new file mode 100644
index 0000000..b786745
--- /dev/null
+++ b/alexa-bridge-skill-lambda/LICENSE.md
@@ -0,0 +1,195 @@
+Copyright (c) 2017 IoTivity
+<http://www.iotivity.org/>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+<http://www.apache.org/licenses/LICENSE-2.0>
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+```
+-------------------------------------------------------------------------
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+```
diff --git a/alexa-bridge-skill-lambda/README.md b/alexa-bridge-skill-lambda/README.md
new file mode 100644
index 0000000..25940b1
--- /dev/null
+++ b/alexa-bridge-skill-lambda/README.md
@@ -0,0 +1,39 @@
+<!---
+ ~ //******************************************************************
+ ~ //
+ ~ // Copyright 2107 Intel Corporation All Rights Reserved.
+ ~ //
+ ~ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ ~ //
+ ~ // Licensed under the Apache License, Version 2.0 (the "License");
+ ~ // you may not use this file except in compliance with the License.
+ ~ // You may obtain a copy of the License at
+ ~ //
+ ~ // http://www.apache.org/licenses/LICENSE-2.0
+ ~ //
+ ~ // Unless required by applicable law or agreed to in writing, software
+ ~ // distributed under the License is distributed on an "AS IS" BASIS,
+ ~ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ // See the License for the specific language governing permissions and
+ ~ // limitations under the License.
+ ~ //
+ ~ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ --->
+
+## Install required node.js modules
+
+You will need to run npm install to create a node_modules folder.
+
+ $ npm install aws-sdk alexa-sdk
+
+Create a zip file with index.js and node_modules.
+
+ $ zip -r aws-lambda-upload.zip index.js node_modules/
+
+aws-lambda-upload.zip will be the zip file for upload.
+
+Subsequent updates to the zip file can be done with
+
+ $ zip aws-lambda-upload.zip index.js
+
+
diff --git a/alexa-bridge-skill-lambda/index.js b/alexa-bridge-skill-lambda/index.js
new file mode 100644
index 0000000..4e1c5c9
--- /dev/null
+++ b/alexa-bridge-skill-lambda/index.js
@@ -0,0 +1,366 @@
+"use strict";
+var config = {};
+
+var AWS = require("aws-sdk");
+var Alexa = require("alexa-sdk");
+
+// replace with endpoint from AWS IoT Device
+var iotData = new AWS.IotData({endpoint:"a2a16j9xf0mmy6.iot.us-east-1.amazonaws.com", region:"us-east-1"});
+// replace with Thing Name for AWS IoT Device
+var thingName = "larryslinuxbox";
+
+var APP_ID = "amzn1.ask.skill.04c3ebae-673e-48ed-8892-bb58feb3eb54";
+var SKILL_NAME = "AlexaIotivityBridgeSkill";
+
+exports.handler = function(event, context, callback) {
+ console.log("Received event:", JSON.stringify(event, null, 2));
+ var alexa = Alexa.handler(event, context);
+ alexa.appId = APP_ID;
+ alexa.registerHandlers(handlers);
+ alexa.execute();
+};
+
+var handlers = {
+ "LaunchRequest": function() {
+ this.emit(":tell", "Bridge Operational");
+ },
+
+ "ListLightsIntent": function() {
+ awsIot.getLights(this);
+ },
+
+ "AllLightsStateIntent": function() {
+ var itemSlot = this.event.request.intent.slots.lightState;
+ var requestedLightState;
+ if (itemSlot && itemSlot.value) {
+ var itemSlotValue = itemSlot.value.toLowerCase();
+ console.log("itemSlotValue: " + itemSlotValue);
+ if (itemSlotValue == "on" || itemSlotValue == "off") {
+ requestedLightState = itemSlotValue;
+ }
+ }
+ console.log("requestedLightState: " + requestedLightState);
+
+ if (!requestedLightState) {
+ this.emit(":tell", "Sorry, I didn't get that");
+ } else {
+ var speechOutput = "All lights " + requestedLightState;
+ awsIot.allLightsStateChange(this, requestedLightState, speechOutput);
+ }
+ },
+
+ "LightBrightnessIntent": function() {
+ var lightName = this.event.request.intent.slots.lightName.value;
+ var lightBrightness = this.event.request.intent.slots.lightBrightness.value;
+ console.log("lightName: " + lightName);
+ console.log("lightBrightness: " + lightBrightness);
+
+ if (!lightName || !lightBrightness) {
+ this.emit(":tell", "Sorry, I didn't get that");
+ } else {
+ awsIot.updateLight(this, postGetLights.updateBrightness, lightName, lightBrightness);
+ }
+ },
+
+ "LightStateIntent": function() {
+ var lightName = this.event.request.intent.slots.lightName.value;
+ var lightState = this.event.request.intent.slots.lightState.value;
+ console.log("lightName: " + lightName);
+ console.log("lightState: " + lightState);
+
+ if (!lightName || !lightState) {
+ this.emit(":tell", "Sorry, I didn't get that");
+ } else {
+ awsIot.updateLight(this, postGetLights.updateOnOff, lightName, lightState);
+ }
+ },
+
+ "LightRenameIntent": function() {
+ var lightName = this.event.request.intent.slots.lightName.value;
+ var newLightName = this.event.request.intent.slots.newLightName.value;
+ console.log("lightName: " + lightName);
+ console.log("newLightName: " + newLightName);
+
+ if (!lightName || !newLightName) {
+ this.emit(":tell", "Sorry, I didn't get that");
+ } else {
+ awsIot.updateLight(this, postGetLights.updateName, lightName, newLightName);
+ }
+ },
+
+ "AMAZON.HelpIntent": function() {
+ this.attributes["speechOutput"] = "You can ask questions such as, 'List Lights', or you can say 'exit'... " +
+ "Now, what can I help you with?";
+ this.attributes["repromptSpeech"] = "You can say things like, 'List Lights', or you can say 'exit'... " +
+ "Now, what can I help you with?";
+ this.emit(":ask", this.attributes["speechOutput"], this.attributes["repromptSpeech"]);
+ },
+
+ "AMAZON.RepeatIntent": function() {
+ this.emit(":ask", this.attributes["speechOutput"], this.attributes["repromptSpeech"]);
+ },
+
+ "AMAZON.StopIntent": function() {
+ this.emit("SessionEndedRequest");
+ },
+
+ "AMAZON.CancelIntent": function() {
+ this.emit("SessionEndedRequest");
+ },
+
+ "SessionEndedRequest":function() {
+ this.emit(":tell", "Goodbye!");
+ }
+};
+
+var awsIot = {
+ postSendMessage: function(thisOfCaller, speechOutput) {
+ console.log("post send message: " + speechOutput);
+ thisOfCaller.emit(":tell", speechOutput);
+ },
+
+ allLightsStateChange: function(thisOfCaller, requestedStateForEachLight, speechOutput) {
+ // update the state for each light
+ var thingNameParam = {
+ thingName: thingName
+ };
+
+ iotData.getThingShadow(thingNameParam, function(err, data) {
+ console.log("get thing shadow (in sendAllOnOff)")
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (err) {
+ speechOutput = "Sorry, no lights found."
+ awsIot.postSendMessage(thisOfCaller, speechOutput);
+ }
+ else {
+ var jsonPayload = JSON.parse(data.payload);
+ var lightDevices = jsonPayload.state.reported.lightDevices;
+ if (lightDevices.length > 0) {
+ lightDevices.forEach((item, index, array) => {
+ console.log("lightDevices["+index+"]: "+JSON.stringify(item));
+ });
+ } else {
+ console.log("no lights found");
+ speechOutput = "Sorry, no lights found.";
+ }
+
+ postGetLights.updateOnOff(thisOfCaller, lightDevices, null, requestedStateForEachLight, speechOutput);
+ }
+ });
+ },
+
+ getLights: function(thisOfCaller) {
+ var speechOutput = "";
+ var thingNameParam = {
+ thingName: thingName
+ };
+
+ iotData.getThingShadow(thingNameParam, function(err, data) {
+ console.log("get thing shadow")
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (err) {
+ speechOutput += " - Error getting device list: " + err + " ";
+ speechOutput += thingNameParam.thingName;
+ } else {
+ var jsonPayload = JSON.parse(data.payload);
+ var lightDevices = jsonPayload.state.reported.lightDevices;
+ if (lightDevices.length > 0) {
+ jsonPayload.state.reported.lightDevices.forEach((item, index, array) => {
+ console.log("lightDevices["+index+"]: "+JSON.stringify(item));
+ if (index > 0) {
+ speechOutput += ", ";
+ }
+ speechOutput += item.name + " is " + (item.powerOn ? "on" : "off");
+ });
+ } else {
+ speechOutput = "Sorry, no lights found."
+ }
+ }
+
+ awsIot.postSendMessage(thisOfCaller, speechOutput);
+ });
+ },
+
+ updateLight: function(thisOfCaller, postGetLights, lightName, lightParam) {
+ var speechOutput = "";
+ var thingNameParam = {
+ thingName: thingName
+ };
+
+ iotData.getThingShadow(thingNameParam, function(err, data) {
+ console.log("get thing shadow (in updateLights)")
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (err) {
+ speechOutput = "Sorry, no lights found."
+ awsIot.postSendMessage(thisOfCaller, speechOutput);
+ }
+ else {
+ var foundLightName = false;
+ var jsonPayload = JSON.parse(data.payload);
+ var lightDevices = jsonPayload.state.reported.lightDevices;
+ if (lightDevices.length > 0) {
+ lightDevices.forEach((item, index, array) => {
+ console.log("lightDevices["+index+"]: "+JSON.stringify(item));
+ if (item.name.toLowerCase() == lightName.toLowerCase()) {
+ console.log("light found -- lightDevices["+index+"]: "+JSON.stringify(item));
+ foundLightName = true;
+ }
+ });
+ } else {
+ console.log("no lights found");
+ }
+ if (foundLightName) {
+ postGetLights(thisOfCaller, lightDevices, lightName, lightParam, speechOutput);
+ } else {
+ speechOutput = "Sorry, I can't find " + lightName;
+ awsIot.postSendMessage(thisOfCaller, speechOutput);
+ }
+ }
+ });
+ }
+};
+
+var postGetLights = {
+ updateBrightness: function(thisOfCaller, lightDevices, lightName, lightParam, speechOutput) {
+ // Set the desired brightness of the light
+ var newLightBrightness;
+ if (lightParam < 0) {
+ newLightBrightness = 0;
+ } else if (lightParam > 100) {
+ newLightBrightness = 100;
+ } else {
+ newLightBrightness = lightParam * 1; // make it a number
+ }
+
+ lightDevices.forEach((item, index, array) => {
+ console.log("lightDevices["+index+"]: "+JSON.stringify(item));
+ if (item.name.toLowerCase() == lightName.toLowerCase()) {
+ lightDevices[index].brightness = newLightBrightness;
+ }
+ console.log("desired lightDevices["+index+"]: "+JSON.stringify(lightDevices[index]));
+ });
+ var desiredLightState =
+ {"state":{"desired":{"device":thingName,"lightDevices":lightDevices}}};
+
+ var thingNameAndPayload = {
+ thingName: thingName,
+ payload: JSON.stringify(desiredLightState)
+ };
+ console.log("payload:", JSON.stringify(desiredLightState, null, 2));
+
+ iotData.updateThingShadow(thingNameAndPayload, function(err, data) {
+ console.log("updateBrightness update thing shadow")
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (err) {
+ speechOutput += " - Error updating light: " + err + " ";
+ speechOutput += thingNameAndPayload.thingName + " ";
+ speechOutput += thingNameAndPayload.payload;
+ } else {
+ speechOutput = lightName + " brightness " + newLightBrightness;
+ }
+ awsIot.postSendMessage(thisOfCaller, speechOutput);
+ });
+ },
+
+ updateOnOff: function(thisOfCaller, lightDevices, lightName, lightParam, speechOutput) {
+ // Set the desired state of the light
+ // lightName of null means all lights
+ console.log("lightName = "+lightName+", !lightName="+(!lightName));
+ var newLightState = (lightParam.toLowerCase() == "on");
+ lightDevices.forEach((item, index, array) => {
+ console.log("lightDevices["+index+"]: "+JSON.stringify(item));
+ if ((! lightName) || (item.name.toLowerCase() == lightName.toLowerCase())) {
+ lightDevices[index].powerOn = newLightState;
+ }
+ console.log("desired lightDevices["+index+"]: "+JSON.stringify(lightDevices[index]));
+ });
+ var desiredLightState =
+ {"state":{"desired":{"device":thingName,"lightDevices":lightDevices}}};
+
+ var thingNameAndPayload = {
+ thingName: thingName,
+ payload: JSON.stringify(desiredLightState)
+ };
+ console.log("payload:", JSON.stringify(desiredLightState, null, 2));
+
+ iotData.updateThingShadow(thingNameAndPayload, function(err, data) {
+ console.log("updateOnOff update thing shadow")
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (err) {
+ speechOutput += " - Error updating light: " + err + " ";
+ speechOutput += thingNameAndPayload.thingName + " ";
+ speechOutput += thingNameAndPayload.payload;
+ } else {
+ if (lightName) {
+ speechOutput = lightName + " " + (newLightState ? "on" : "off");
+ }
+ }
+ awsIot.postSendMessage(thisOfCaller, speechOutput);
+ });
+ },
+
+ updateName: function(thisOfCaller, lightDevices, lightName, lightParam, speechOutput) {
+ // Set the desired name of the light
+ var newLightName = lightParam;
+
+ lightDevices.forEach((item, index, array) => {
+ console.log("lightDevices["+index+"]: "+JSON.stringify(item));
+ if (item.name.toLowerCase() == lightName.toLowerCase()) {
+ lightDevices[index].name = newLightName;
+ }
+ console.log("desired lightDevices["+index+"]: "+JSON.stringify(lightDevices[index]));
+ });
+
+ // sort desired light devices by name (ignoring case)
+ lightDevices.sort((lhs, rhs) => {
+ var lhsName = lhs.name.toLowerCase();
+ var rhsName = rhs.name.toLowerCase();
+
+ if (lhsName < rhsName) {
+ return -1;
+ }
+ if (lhsName > rhsName) {
+ return 1;
+ }
+ // names must be equal
+ return 0;
+ });
+ lightDevices.forEach((item, index, array) => {
+ console.log("sorted desired lightDevices["+index+"]: "+JSON.stringify(item));
+ });
+
+ var desiredLightState =
+ {"state":{"desired":{"device":thingName,"lightDevices":lightDevices}}};
+
+ var thingNameAndPayload = {
+ thingName: thingName,
+ payload: JSON.stringify(desiredLightState)
+ };
+ console.log("payload:", JSON.stringify(desiredLightState, null, 2));
+
+ iotData.updateThingShadow(thingNameAndPayload, function(err, data) {
+ console.log("updateName update thing shadow")
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (err) {
+ speechOutput += " - Error updating light: " + err + " ";
+ speechOutput += thingNameAndPayload.thingName + " ";
+ speechOutput += thingNameAndPayload.payload;
+ } else {
+ speechOutput = lightName + " renamed as " + newLightName;
+ }
+ awsIot.postSendMessage(thisOfCaller, speechOutput);
+ });
+ }
+};
diff --git a/alexa-bridge-skill-lambda/intents.json b/alexa-bridge-skill-lambda/intents.json
new file mode 100644
index 0000000..cc76e39
--- /dev/null
+++ b/alexa-bridge-skill-lambda/intents.json
@@ -0,0 +1,161 @@
+{
+ "languageModel": {
+ "types": [
+ {
+ "name": "lightName",
+ "values": [
+ {
+ "id": null,
+ "name": {
+ "value": "name",
+ "synonyms": []
+ }
+ },
+ {
+ "id": null,
+ "name": {
+ "value": "light's name",
+ "synonyms": []
+ }
+ },
+ {
+ "id": null,
+ "name": {
+ "value": "name of light",
+ "synonyms": []
+ }
+ },
+ {
+ "id": null,
+ "name": {
+ "value": "long name of light",
+ "synonyms": []
+ }
+ },
+ {
+ "id": null,
+ "name": {
+ "value": "really long name of light",
+ "synonyms": []
+ }
+ },
+ {
+ "id": null,
+ "name": {
+ "value": "all",
+ "synonyms": []
+ }
+ }
+ ]
+ },
+ {
+ "name": "lightState",
+ "values": [
+ {
+ "id": "ON",
+ "name": {
+ "value": "on",
+ "synonyms": []
+ }
+ },
+ {
+ "id": "OFF",
+ "name": {
+ "value": "off",
+ "synonyms": []
+ }
+ }
+ ]
+ }
+ ],
+ "intents": [
+ {
+ "name": "AllLightsStateIntent",
+ "samples": [
+ "Lights {lightState}",
+ "All lights {lightState}"
+ ],
+ "slots": [
+ {
+ "name": "lightState",
+ "type": "lightState"
+ }
+ ]
+ },
+ {
+ "name": "AMAZON.CancelIntent",
+ "samples": []
+ },
+ {
+ "name": "AMAZON.HelpIntent",
+ "samples": []
+ },
+ {
+ "name": "AMAZON.StopIntent",
+ "samples": []
+ },
+ {
+ "name": "LightBrightnessIntent",
+ "samples": [
+ "{lightName} brightness {lightBrightness}"
+ ],
+ "slots": [
+ {
+ "name": "lightName",
+ "type": "lightName"
+ },
+ {
+ "name": "lightBrightness",
+ "type": "AMAZON.NUMBER"
+ }
+ ]
+ },
+ {
+ "name": "LightRenameIntent",
+ "samples": [
+ "Rename {lightName} as {newLightName}",
+ "Rename {lightName} to {newLightName}",
+ "Change {lightName} to {newLightName}"
+ ],
+ "slots": [
+ {
+ "name": "lightName",
+ "type": "lightName"
+ },
+ {
+ "name": "newLightName",
+ "type": "lightName"
+ }
+ ]
+ },
+ {
+ "name": "LightStateIntent",
+ "samples": [
+ "{lightName} state {lightState}",
+ "{lightName} switch {lightState}",
+ "{lightName} power {lightState}",
+ "Switch {lightName} {lightState}",
+ "Power {lightName} {lightState}"
+ ],
+ "slots": [
+ {
+ "name": "lightName",
+ "type": "lightName"
+ },
+ {
+ "name": "lightState",
+ "type": "lightState"
+ }
+ ]
+ },
+ {
+ "name": "ListLightsIntent",
+ "samples": [
+ "List Lights"
+ ],
+ "slots": []
+ }
+ ],
+ "invocationName": "bridge"
+ }
+} \ No newline at end of file
diff --git a/alexa-iotivity-bridge-demo/LICENSE.md b/alexa-iotivity-bridge-demo/LICENSE.md
new file mode 100644
index 0000000..b786745
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/LICENSE.md
@@ -0,0 +1,195 @@
+Copyright (c) 2017 IoTivity
+<http://www.iotivity.org/>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+<http://www.apache.org/licenses/LICENSE-2.0>
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+```
+-------------------------------------------------------------------------
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+```
diff --git a/alexa-iotivity-bridge-demo/README.md b/alexa-iotivity-bridge-demo/README.md
new file mode 100644
index 0000000..2c4f975
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/README.md
@@ -0,0 +1,39 @@
+<!---
+ ~ //******************************************************************
+ ~ //
+ ~ // Copyright 2107 Intel Corporation All Rights Reserved.
+ ~ //
+ ~ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ ~ //
+ ~ // Licensed under the Apache License, Version 2.0 (the "License");
+ ~ // you may not use this file except in compliance with the License.
+ ~ // You may obtain a copy of the License at
+ ~ //
+ ~ // http://www.apache.org/licenses/LICENSE-2.0
+ ~ //
+ ~ // Unless required by applicable law or agreed to in writing, software
+ ~ // distributed under the License is distributed on an "AS IS" BASIS,
+ ~ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ // See the License for the specific language governing permissions and
+ ~ // limitations under the License.
+ ~ //
+ ~ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ --->
+
+## Install required build libraries
+
+You will need to build IoTivity prior to use.
+
+ $ scons TARGET_TRANSPORT=IP SECURED=0 BUILD_JAVA=ON
+
+Once built, the build.sh and run.sh scripts expect iotivity.jar to be copied to ./lib directory.
+
+ $ cp <iotivity>/out/linux/x86_64/release/java/iotivity.jar lib/.
+
+## Build
+
+ $ ./build.sh
+
+## Run
+
+ $ ./run.sh
diff --git a/alexa-iotivity-bridge-demo/build.sh b/alexa-iotivity-bridge-demo/build.sh
new file mode 100755
index 0000000..5c78ab3
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/build.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+#find ./out -type f -name '*.class' -delete
+rm -rf ./out
+mkdir out
+javac @options.txt @sourcefiles.txt
+
+#jar -cfv AlexaIotivityBridgeDemo.jar -C out/ .
+jar -cf AlexaIotivityBridgeDemo.jar -C out/ .
+
diff --git a/alexa-iotivity-bridge-demo/options.txt b/alexa-iotivity-bridge-demo/options.txt
new file mode 100644
index 0000000..fe545c1
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/options.txt
@@ -0,0 +1,2 @@
+-cp ./lib/aws-iot-device-sdk-java-1.1.1.jar:./lib/jackson-core-2.9.0.jar:./lib/jackson-annotations-2.9.0.jar:./lib/jackson-databind-2.9.0.jar:./lib/org.eclipse.paho.client.mqttv3-1.2.0.jar:./lib/iotivity.jar
+-d ./out/
diff --git a/alexa-iotivity-bridge-demo/run.sh b/alexa-iotivity-bridge-demo/run.sh
new file mode 100755
index 0000000..e14441a
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/run.sh
@@ -0,0 +1,3 @@
+# -cp assumes iotivity.jar has been copied into ./lib/
+
+java -Djava.library.path=/home/larrys/work/iotivity-1.3-rel/iotivity/out/linux/x86_64/release -cp AlexaIotivityBridgeDemo.jar:./lib/iotivity.jar:./lib/aws-iot-device-sdk-java-1.1.1.jar:./lib/jackson-core-2.9.0.jar:./lib/jackson-annotations-2.9.0.jar:./lib/jackson-databind-2.9.0.jar:./lib/org.eclipse.paho.client.mqttv3-1.2.0.jar org.iotivity.base.examples.AlexaIotivityBridgeDemo -clientEndpoint a2a16j9xf0mmy6.iot.us-east-1.amazonaws.com -clientId arn:aws:iot:us-east-1:834884142022:thing/larryslinuxbox -certificateFile /home/larrys/work/connect_device_package/larryslinuxbox.cert.pem -privateKeyFile /home/larrys/work/connect_device_package/larryslinuxbox.private.key -thingName larryslinuxbox
diff --git a/alexa-iotivity-bridge-demo/runscanner.sh b/alexa-iotivity-bridge-demo/runscanner.sh
new file mode 100755
index 0000000..3bb2327
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/runscanner.sh
@@ -0,0 +1,3 @@
+# -cp assumes iotivity.jar has been copied into ./lib/
+
+java -Djava.library.path=/home/larrys/work/iotivity-1.3-rel/iotivity/out/linux/x86_64/release -cp AlexaIotivityBridgeDemo.jar:./lib/iotivity.jar org.iotivity.base.examples.IotivityScanner $1 \ No newline at end of file
diff --git a/alexa-iotivity-bridge-demo/sourcefiles.txt b/alexa-iotivity-bridge-demo/sourcefiles.txt
new file mode 100644
index 0000000..0579af5
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/sourcefiles.txt
@@ -0,0 +1,23 @@
+./src/main/java/org/iotivity/base/examples/AlexaIotivityBridgeDemo.java
+./src/main/java/org/iotivity/base/examples/IotivityClient.java
+./src/main/java/org/iotivity/base/examples/UpdatePublisherListener.java
+./src/main/java/org/iotivity/base/examples/UpdateAcceptedTopicListener.java
+./src/main/java/org/iotivity/base/examples/ConnectedThing.java
+./src/main/java/org/iotivity/base/examples/Resource.java
+./src/main/java/org/iotivity/base/examples/Device.java
+./src/main/java/org/iotivity/base/examples/Service.java
+./src/main/java/org/iotivity/base/examples/BinarySwitch.java
+./src/main/java/org/iotivity/base/examples/Brightness.java
+./src/main/java/org/iotivity/base/examples/Configuration.java
+./src/main/java/org/iotivity/base/examples/Light.java
+./src/main/java/org/iotivity/base/examples/Links.java
+./src/main/java/org/iotivity/base/examples/Link.java
+./src/main/java/org/iotivity/base/examples/NamesPropertyFile.java
+./src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/SampleUtil.java
+./src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/CommandArguments.java
+./src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/PrivateKeyReader.java
+./src/main/java/org/iotivity/base/examples/IotivityScanner.java
+./src/main/java/org/iotivity/base/examples/IotivityScannerClient.java
+
+
+
diff --git a/alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/CommandArguments.java b/alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/CommandArguments.java
new file mode 100644
index 0000000..1060963
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/CommandArguments.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.amazonaws.services.iot.client.sample.sampleUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CommandArguments {
+
+ private final Map<String, String> arguments = new HashMap<String, String>();
+
+ private CommandArguments(String[] args) {
+ String name = null;
+
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i].trim();
+ if (name == null) {
+ if (arg.startsWith("-")) {
+ name = arg.replaceFirst("^-+", "");
+ if (name.length() < 1) {
+ name = null;
+ }
+ }
+ continue;
+ }
+
+ if (arg.startsWith("-")) {
+ arguments.put(name.toLowerCase(), null);
+
+ name = arg.replaceFirst("^-+", "");
+ if (name.length() < 1) {
+ name = null;
+ }
+ } else {
+ arguments.put(name.toLowerCase(), arg);
+ name = null;
+ }
+ }
+
+ if (name != null) {
+ arguments.put(name.toLowerCase(), null);
+ }
+ }
+
+ public static CommandArguments parse(String[] args) {
+ return new CommandArguments(args);
+ }
+
+ public String get(String name) {
+ return arguments.get(name.toLowerCase());
+ }
+
+ public String get(String name, String defaultValue) {
+ String value = arguments.get(name.toLowerCase());
+ if (value == null) {
+ value = defaultValue;
+ }
+ return value;
+ }
+
+ public String getNotNull(String name) {
+ String value = get(name);
+ if (value == null) {
+ throw new RuntimeException("Missing required argumment for " + name);
+ }
+ return value;
+ }
+
+ public String getNotNull(String name, String defaultValue) {
+ String value = get(name, defaultValue);
+ if (value == null) {
+ throw new RuntimeException("Missing required argumment for " + name);
+ }
+ return value;
+ }
+
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/PrivateKeyReader.java b/alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/PrivateKeyReader.java
new file mode 100644
index 0000000..dd4be85
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/PrivateKeyReader.java
@@ -0,0 +1,491 @@
+/****************************************************************************
+ * Amazon Modifications: Copyright 2016 Amazon.com, Inc. or its affiliates.
+ * All Rights Reserved.
+ *****************************************************************************
+ * Copyright (c) 1998-2010 AOL Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ****************************************************************************/
+// http://oauth.googlecode.com/svn/code/branches/jmeter/jmeter/src/main/java/org/apache/jmeter/protocol/oauth/sampler/PrivateKeyReader.java
+
+package com.amazonaws.services.iot.client.sample.sampleUtil;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import javax.xml.bind.DatatypeConverter;
+
+/**
+ * Class for reading RSA or ECC private key from PEM file.
+ *
+ * It can read PEM files with PKCS#8 or PKCS#1 encodings. It doesn't support
+ * encrypted PEM files.
+ */
+public class PrivateKeyReader {
+
+ // Private key file using PKCS #1 encoding
+ public static final String P1_BEGIN_MARKER = "-----BEGIN RSA PRIVATE KEY"; //$NON-NLS-1$
+ public static final String P1_END_MARKER = "-----END RSA PRIVATE KEY"; //$NON-NLS-1$
+
+ // Private key file using PKCS #8 encoding
+ public static final String P8_BEGIN_MARKER = "-----BEGIN PRIVATE KEY"; //$NON-NLS-1$
+ public static final String P8_END_MARKER = "-----END PRIVATE KEY"; //$NON-NLS-1$
+
+ /**
+ * Get a RSA Private Key from InputStream.
+ *
+ * @param fileName
+ * file name
+ * @return Private key
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ * @throws GeneralSecurityException
+ * GeneralSecurityException resulted from invalid key format
+ */
+ public static PrivateKey getPrivateKey(String fileName) throws IOException, GeneralSecurityException {
+ try (InputStream stream = new FileInputStream(fileName)) {
+ return getPrivateKey(stream, null);
+ }
+ }
+
+ /**
+ * Get a Private Key from InputStream.
+ *
+ * @param fileName
+ * file name
+ * @param algorithm
+ * the name of the key algorithm, for example "RSA" or "EC"
+ * @return Private key
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ * @throws GeneralSecurityException
+ * GeneralSecurityException resulted from invalid key data
+ */
+ public static PrivateKey getPrivateKey(String fileName, String algorithm) throws IOException,
+ GeneralSecurityException {
+ try (InputStream stream = new FileInputStream(fileName)) {
+ return getPrivateKey(stream, algorithm);
+ }
+ }
+
+ /**
+ * Get a Private Key for the file.
+ *
+ * @param stream
+ * InputStream object
+ * @param algorithm
+ * the name of the key algorithm, for example "RSA" or "EC"
+ * @return Private key
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ * @throws GeneralSecurityException
+ * GeneralSecurityException resulted from invalid key data
+ */
+ public static PrivateKey getPrivateKey(InputStream stream, String algorithm) throws IOException,
+ GeneralSecurityException {
+ PrivateKey key = null;
+ boolean isRSAKey = false;
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
+ StringBuilder builder = new StringBuilder();
+ boolean inKey = false;
+ for (String line = br.readLine(); line != null; line = br.readLine()) {
+ if (!inKey) {
+ if (line.startsWith("-----BEGIN ") && line.endsWith(" PRIVATE KEY-----")) {
+ inKey = true;
+ isRSAKey = line.contains("RSA");
+ }
+ continue;
+ } else {
+ if (line.startsWith("-----END ") && line.endsWith(" PRIVATE KEY-----")) {
+ inKey = false;
+ isRSAKey = line.contains("RSA");
+ break;
+ }
+ builder.append(line);
+ }
+ }
+ KeySpec keySpec = null;
+ byte[] encoded = DatatypeConverter.parseBase64Binary(builder.toString());
+ if (isRSAKey) {
+ keySpec = getRSAKeySpec(encoded);
+ } else {
+ keySpec = new PKCS8EncodedKeySpec(encoded);
+ }
+ KeyFactory kf = KeyFactory.getInstance((algorithm == null) ? "RSA" : algorithm);
+ key = kf.generatePrivate(keySpec);
+
+ return key;
+ }
+
+ /**
+ * Convert PKCS#1 encoded private key into RSAPrivateCrtKeySpec.
+ *
+ * <p/>
+ * The ASN.1 syntax for the private key with CRT is
+ *
+ * <pre>
+ * --
+ * -- Representation of RSA private key with information for the CRT algorithm.
+ * --
+ * RSAPrivateKey ::= SEQUENCE {
+ * version Version,
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ * </pre>
+ *
+ * @param keyBytes
+ * PKCS#1 encoded key
+ * @return KeySpec
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ */
+ private static RSAPrivateCrtKeySpec getRSAKeySpec(byte[] keyBytes) throws IOException {
+
+ DerParser parser = new DerParser(keyBytes);
+
+ Asn1Object sequence = parser.read();
+ if (sequence.getType() != DerParser.SEQUENCE)
+ throw new IOException("Invalid DER: not a sequence"); //$NON-NLS-1$
+
+ // Parse inside the sequence
+ parser = sequence.getParser();
+
+ parser.read(); // Skip version
+ BigInteger modulus = parser.read().getInteger();
+ BigInteger publicExp = parser.read().getInteger();
+ BigInteger privateExp = parser.read().getInteger();
+ BigInteger prime1 = parser.read().getInteger();
+ BigInteger prime2 = parser.read().getInteger();
+ BigInteger exp1 = parser.read().getInteger();
+ BigInteger exp2 = parser.read().getInteger();
+ BigInteger crtCoef = parser.read().getInteger();
+
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, exp1,
+ exp2, crtCoef);
+
+ return keySpec;
+ }
+}
+
+/**
+ * A bare-minimum ASN.1 DER decoder, just having enough functions to decode
+ * PKCS#1 private keys. Especially, it doesn't handle explicitly tagged types
+ * with an outer tag.
+ *
+ * <p/>
+ * This parser can only handle one layer. To parse nested constructs, get a new
+ * parser for each layer using <code>Asn1Object.getParser()</code>.
+ *
+ * <p/>
+ * There are many DER decoders in JRE but using them will tie this program to a
+ * specific JCE/JVM.
+ *
+ * @author zhang
+ *
+ */
+class DerParser {
+
+ // Classes
+ public final static int UNIVERSAL = 0x00;
+ public final static int APPLICATION = 0x40;
+ public final static int CONTEXT = 0x80;
+ public final static int PRIVATE = 0xC0;
+
+ // Constructed Flag
+ public final static int CONSTRUCTED = 0x20;
+
+ // Tag and data types
+ public final static int ANY = 0x00;
+ public final static int BOOLEAN = 0x01;
+ public final static int INTEGER = 0x02;
+ public final static int BIT_STRING = 0x03;
+ public final static int OCTET_STRING = 0x04;
+ public final static int NULL = 0x05;
+ public final static int OBJECT_IDENTIFIER = 0x06;
+ public final static int REAL = 0x09;
+ public final static int ENUMERATED = 0x0a;
+ public final static int RELATIVE_OID = 0x0d;
+
+ public final static int SEQUENCE = 0x10;
+ public final static int SET = 0x11;
+
+ public final static int NUMERIC_STRING = 0x12;
+ public final static int PRINTABLE_STRING = 0x13;
+ public final static int T61_STRING = 0x14;
+ public final static int VIDEOTEX_STRING = 0x15;
+ public final static int IA5_STRING = 0x16;
+ public final static int GRAPHIC_STRING = 0x19;
+ public final static int ISO646_STRING = 0x1A;
+ public final static int GENERAL_STRING = 0x1B;
+
+ public final static int UTF8_STRING = 0x0C;
+ public final static int UNIVERSAL_STRING = 0x1C;
+ public final static int BMP_STRING = 0x1E;
+
+ public final static int UTC_TIME = 0x17;
+ public final static int GENERALIZED_TIME = 0x18;
+
+ protected InputStream in;
+
+ /**
+ * Create a new DER decoder from an input stream.
+ *
+ * @param in
+ * The DER encoded stream
+ */
+ public DerParser(InputStream in) throws IOException {
+ this.in = in;
+ }
+
+ /**
+ * Create a new DER decoder from a byte array.
+ *
+ * @param The
+ * encoded bytes
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ */
+ public DerParser(byte[] bytes) throws IOException {
+ this(new ByteArrayInputStream(bytes));
+ }
+
+ /**
+ * Read next object. If it's constructed, the value holds encoded content
+ * and it should be parsed by a new parser from
+ * <code>Asn1Object.getParser</code>.
+ *
+ * @return A object
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ */
+ public Asn1Object read() throws IOException {
+ int tag = in.read();
+
+ if (tag == -1)
+ throw new IOException("Invalid DER: stream too short, missing tag"); //$NON-NLS-1$
+
+ int length = getLength();
+
+ byte[] value = new byte[length];
+ int n = in.read(value);
+ if (n < length)
+ throw new IOException("Invalid DER: stream too short, missing value"); //$NON-NLS-1$
+
+ Asn1Object o = new Asn1Object(tag, length, value);
+
+ return o;
+ }
+
+ /**
+ * Decode the length of the field. Can only support length encoding up to 4
+ * octets.
+ *
+ * <p/>
+ * In BER/DER encoding, length can be encoded in 2 forms,
+ * <ul>
+ * <li>Short form. One octet. Bit 8 has value "0" and bits 7-1 give the
+ * length.
+ * <li>Long form. Two to 127 octets (only 4 is supported here). Bit 8 of
+ * first octet has value "1" and bits 7-1 give the number of additional
+ * length octets. Second and following octets give the length, base 256,
+ * most significant digit first.
+ * </ul>
+ *
+ * @return The length as integer
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ */
+ private int getLength() throws IOException {
+
+ int i = in.read();
+ if (i == -1)
+ throw new IOException("Invalid DER: length missing"); //$NON-NLS-1$
+
+ // A single byte short length
+ if ((i & ~0x7F) == 0)
+ return i;
+
+ int num = i & 0x7F;
+
+ // We can't handle length longer than 4 bytes
+ if (i >= 0xFF || num > 4)
+ throw new IOException("Invalid DER: length field too big (" //$NON-NLS-1$
+ + i + ")"); //$NON-NLS-1$
+
+ byte[] bytes = new byte[num];
+ int n = in.read(bytes);
+ if (n < num)
+ throw new IOException("Invalid DER: length too short"); //$NON-NLS-1$
+
+ return new BigInteger(1, bytes).intValue();
+ }
+
+}
+
+/**
+ * An ASN.1 TLV. The object is not parsed. It can only handle integers and
+ * strings.
+ *
+ * @author zhang
+ *
+ */
+class Asn1Object {
+
+ protected final int type;
+ protected final int length;
+ protected final byte[] value;
+ protected final int tag;
+
+ /**
+ * Construct a ASN.1 TLV. The TLV could be either a constructed or primitive
+ * entity.
+ *
+ * <p/>
+ * The first byte in DER encoding is made of following fields,
+ *
+ * <pre>
+ * -------------------------------------------------
+ * |Bit 8|Bit 7|Bit 6|Bit 5|Bit 4|Bit 3|Bit 2|Bit 1|
+ * -------------------------------------------------
+ * | Class | CF | + Type |
+ * -------------------------------------------------
+ * </pre>
+ *
+ * <ul>
+ * <li>Class: Universal, Application, Context or Private
+ * <li>CF: Constructed flag. If 1, the field is constructed.
+ * <li>Type: This is actually called tag in ASN.1. It indicates data type
+ * (Integer, String) or a construct (sequence, choice, set).
+ * </ul>
+ *
+ * @param tag
+ * Tag or Identifier
+ * @param length
+ * Length of the field
+ * @param value
+ * Encoded octet string for the field.
+ */
+ public Asn1Object(int tag, int length, byte[] value) {
+ this.tag = tag;
+ this.type = tag & 0x1F;
+ this.length = length;
+ this.value = value;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public byte[] getValue() {
+ return value;
+ }
+
+ public boolean isConstructed() {
+ return (tag & DerParser.CONSTRUCTED) == DerParser.CONSTRUCTED;
+ }
+
+ /**
+ * For constructed field, return a parser for its content.
+ *
+ * @return A parser for the construct.
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ */
+ public DerParser getParser() throws IOException {
+ if (!isConstructed())
+ throw new IOException("Invalid DER: can't parse primitive entity"); //$NON-NLS-1$
+
+ return new DerParser(value);
+ }
+
+ /**
+ * Get the value as integer
+ *
+ * @return BigInteger
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ */
+ public BigInteger getInteger() throws IOException {
+ if (type != DerParser.INTEGER)
+ throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$
+
+ return new BigInteger(value);
+ }
+
+ /**
+ * Get value as string. Most strings are treated as Latin-1.
+ *
+ * @return Java string
+ * @throws IOException
+ * IOException resulted from invalid file IO
+ */
+ public String getString() throws IOException {
+
+ String encoding;
+
+ switch (type) {
+
+ // Not all are Latin-1 but it's the closest thing
+ case DerParser.NUMERIC_STRING:
+ case DerParser.PRINTABLE_STRING:
+ case DerParser.VIDEOTEX_STRING:
+ case DerParser.IA5_STRING:
+ case DerParser.GRAPHIC_STRING:
+ case DerParser.ISO646_STRING:
+ case DerParser.GENERAL_STRING:
+ encoding = "ISO-8859-1"; //$NON-NLS-1$
+ break;
+
+ case DerParser.BMP_STRING:
+ encoding = "UTF-16BE"; //$NON-NLS-1$
+ break;
+
+ case DerParser.UTF8_STRING:
+ encoding = "UTF-8"; //$NON-NLS-1$
+ break;
+
+ case DerParser.UNIVERSAL_STRING:
+ throw new IOException("Invalid DER: can't handle UCS-4 string"); //$NON-NLS-1$
+
+ default:
+ throw new IOException("Invalid DER: object is not a string"); //$NON-NLS-1$
+ }
+
+ return new String(value, encoding);
+ }
+} \ No newline at end of file
diff --git a/alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/SampleUtil.java b/alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/SampleUtil.java
new file mode 100644
index 0000000..0cae498
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/com/amazonaws/services/iot/client/sample/sampleUtil/SampleUtil.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.amazonaws.services.iot.client.sample.sampleUtil;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * This is a helper class to facilitate reading of the configurations and
+ * certificate from the resource files.
+ */
+public class SampleUtil {
+ private static final String PropertyFile = "aws-iot-sdk-samples.properties";
+
+ public static class KeyStorePasswordPair {
+ public KeyStore keyStore;
+ public String keyPassword;
+
+ public KeyStorePasswordPair(KeyStore keyStore, String keyPassword) {
+ this.keyStore = keyStore;
+ this.keyPassword = keyPassword;
+ }
+ }
+
+ public static String getConfig(String name) {
+ Properties prop = new Properties();
+ URL resource = SampleUtil.class.getResource(PropertyFile);
+ if (resource == null) {
+ return null;
+ }
+ try (InputStream stream = resource.openStream()) {
+ prop.load(stream);
+ } catch (IOException e) {
+ return null;
+ }
+ String value = prop.getProperty(name);
+ if (value == null || value.trim().length() == 0) {
+ return null;
+ } else {
+ return value;
+ }
+ }
+
+ public static KeyStorePasswordPair getKeyStorePasswordPair(final String certificateFile, final String privateKeyFile) {
+ return getKeyStorePasswordPair(certificateFile, privateKeyFile, null);
+ }
+
+ public static KeyStorePasswordPair getKeyStorePasswordPair(final String certificateFile, final String privateKeyFile,
+ String keyAlgorithm) {
+ if (certificateFile == null || privateKeyFile == null) {
+ System.out.println("Certificate or private key file missing");
+ return null;
+ }
+ System.out.println("Cert file:" +certificateFile + " Private key: "+ privateKeyFile);
+
+ final PrivateKey privateKey = loadPrivateKeyFromFile(privateKeyFile, keyAlgorithm);
+
+ final List<Certificate> certChain = loadCertificatesFromFile(certificateFile);
+
+ if (certChain == null || privateKey == null) return null;
+
+ return getKeyStorePasswordPair(certChain, privateKey);
+ }
+
+ public static KeyStorePasswordPair getKeyStorePasswordPair(final List<Certificate> certificates, final PrivateKey privateKey) {
+ KeyStore keyStore;
+ String keyPassword;
+ try {
+ keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ keyStore.load(null);
+
+ // randomly generated key password for the key in the KeyStore
+ keyPassword = new BigInteger(128, new SecureRandom()).toString(32);
+
+ Certificate[] certChain = new Certificate[certificates.size()];
+ certChain = certificates.toArray(certChain);
+ keyStore.setKeyEntry("alias", privateKey, keyPassword.toCharArray(), certChain);
+ } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
+ System.out.println("Failed to create key store");
+ return null;
+ }
+
+ return new KeyStorePasswordPair(keyStore, keyPassword);
+ }
+
+ private static List<Certificate> loadCertificatesFromFile(final String filename) {
+ File file = new File(filename);
+ if (!file.exists()) {
+ System.out.println("Certificate file: " + filename + " is not found.");
+ return null;
+ }
+
+ try (BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file))) {
+ final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ return (List<Certificate>) certFactory.generateCertificates(stream);
+ } catch (IOException | CertificateException e) {
+ System.out.println("Failed to load certificate file " + filename);
+ }
+ return null;
+ }
+
+ private static PrivateKey loadPrivateKeyFromFile(final String filename, final String algorithm) {
+ PrivateKey privateKey = null;
+
+ File file = new File(filename);
+ if (!file.exists()) {
+ System.out.println("Private key file not found: " + filename);
+ return null;
+ }
+ try (DataInputStream stream = new DataInputStream(new FileInputStream(file))) {
+ privateKey = PrivateKeyReader.getPrivateKey(stream, algorithm);
+ } catch (IOException | GeneralSecurityException e) {
+ System.out.println("Failed to load private key from file " + filename);
+ }
+
+ return privateKey;
+ }
+
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/AlexaIotivityBridgeDemo.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/AlexaIotivityBridgeDemo.java
new file mode 100644
index 0000000..093c521
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/AlexaIotivityBridgeDemo.java
@@ -0,0 +1,186 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.ModeType;
+import org.iotivity.base.OcConnectivityType;
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.PlatformConfig;
+import org.iotivity.base.QualityOfService;
+import org.iotivity.base.ServiceType;
+
+import com.amazonaws.services.iot.client.AWSIotMqttClient;
+import com.amazonaws.services.iot.client.AWSIotQos;
+import com.amazonaws.services.iot.client.AWSIotConnectionStatus;
+import com.amazonaws.services.iot.client.AWSIotException;
+import com.amazonaws.services.iot.client.AWSIotMessage;
+import com.amazonaws.services.iot.client.AWSIotTimeoutException;
+import com.amazonaws.services.iot.client.AWSIotTopic;
+
+import com.amazonaws.services.iot.client.sample.sampleUtil.CommandArguments;
+import com.amazonaws.services.iot.client.sample.sampleUtil.SampleUtil;
+import com.amazonaws.services.iot.client.sample.sampleUtil.SampleUtil.KeyStorePasswordPair;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.EnumSet;
+
+/**
+ * AlexaIotivityBridgeDemo
+ *
+ * AlexaIotivityBridgeDemo is a client app which finds resources
+ * advertised by the server pushes them to the cloud and waits
+ * for update requests.
+ */
+public class AlexaIotivityBridgeDemo {
+
+ private static final String UpdateTopic = "$aws/things/larryslinuxbox/shadow/update";
+ private static final String UpdateAcceptedTopic = "$aws/things/larryslinuxbox/shadow/update/accepted";
+ private static final AWSIotQos TopicQos = AWSIotQos.QOS0;
+
+ private static AWSIotMqttClient awsIotClient;
+ private static IotivityClient iotivityClient;
+
+ // initClient() is copied from aws iot sdk samples.
+ private static void initAwsIotClient(CommandArguments arguments) {
+ String clientEndpoint = arguments.getNotNull("clientEndpoint", SampleUtil.getConfig("clientEndpoint"));
+ String clientId = arguments.getNotNull("clientId", SampleUtil.getConfig("clientId"));
+
+ String certificateFile = arguments.get("certificateFile", SampleUtil.getConfig("certificateFile"));
+ String privateKeyFile = arguments.get("privateKeyFile", SampleUtil.getConfig("privateKeyFile"));
+ if (awsIotClient == null && certificateFile != null && privateKeyFile != null) {
+ String algorithm = arguments.get("keyAlgorithm", SampleUtil.getConfig("keyAlgorithm"));
+ KeyStorePasswordPair pair = SampleUtil.getKeyStorePasswordPair(certificateFile, privateKeyFile, algorithm);
+
+ awsIotClient = new AWSIotMqttClient(clientEndpoint, clientId, pair.keyStore, pair.keyPassword);
+ }
+
+ if (awsIotClient == null) {
+ throw new IllegalArgumentException("Failed to construct client due to missing certificate or credentials.");
+ }
+ }
+
+ /**
+ * Configure and initialize platform.
+ */
+ private static void startIotivityClient() {
+
+ PlatformConfig platformConfig = new PlatformConfig(
+ ServiceType.IN_PROC,
+ ModeType.CLIENT,
+ "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
+ 0, // Uses randomly available port
+ QualityOfService.LOW
+ );
+ msg("Configuring platform.");
+ OcPlatform.Configure(platformConfig);
+
+ iotivityClient = new IotivityClient();
+ }
+
+ public static void main(String args[]) throws IOException, AWSIotException, AWSIotTimeoutException, InterruptedException {
+ CommandArguments arguments = CommandArguments.parse(args);
+ initAwsIotClient(arguments); // creates awsIotClient
+
+ startIotivityClient(); // creates iotivityClient
+
+ awsIotClient.setWillMessage(new AWSIotMessage("client/disconnect", AWSIotQos.QOS0, awsIotClient.getClientId()));
+
+ String thingName = arguments.getNotNull("thingName", SampleUtil.getConfig("thingName"));
+ ConnectedThing connectedThing = new ConnectedThing(thingName, iotivityClient);
+
+ awsIotClient.attach(connectedThing);
+ awsIotClient.connect();
+
+ // Delete existing document if any
+ connectedThing.delete();
+
+ AWSIotTopic topic = new UpdateAcceptedTopicListener(UpdateAcceptedTopic, TopicQos);
+ awsIotClient.subscribe(topic, false);
+
+ iotivityClient.setConnectedThing(connectedThing);
+
+ AWSIotConnectionStatus status = AWSIotConnectionStatus.DISCONNECTED;
+
+ while (true) {
+ AWSIotConnectionStatus newStatus = awsIotClient.getConnectionStatus();
+ if (!status.equals(newStatus)) {
+ AlexaIotivityBridgeDemo.msg("Connection status changed to " + newStatus);
+ status = newStatus;
+ }
+
+ try {
+// msg("Finding all resources of type " + Light.OIC_TYPE_DEVICE_LIGHT);
+ String requestUri = OcPlatform.WELL_KNOWN_QUERY + "?rt=" + Light.OIC_TYPE_DEVICE_LIGHT;
+ OcPlatform.findResources("", requestUri, EnumSet.of(OcConnectivityType.CT_DEFAULT), iotivityClient);
+
+ } catch (OcException e) {
+ msgError(e.toString());
+ msgError("Failed to invoke find resource API");
+ }
+
+ sleep(10);
+
+ iotivityClient.cancelObserve();
+ }
+ }
+
+ public static void publishUpdatePayload(final String payload) {
+ AWSIotMessage message = new UpdatePublisherListener(UpdateTopic, TopicQos, payload);
+
+ try {
+ awsIotClient.publish(message);
+ } catch (AWSIotException e) {
+ AlexaIotivityBridgeDemo.msgError("publish failed for " + payload);
+ }
+ }
+
+ private static void sleep(int seconds) {
+ try {
+ Thread.sleep(seconds * 1000);
+ } catch (InterruptedException e) {
+ msgError(e.toString());
+ }
+ }
+
+ public static void msg(final String text) {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+ Date date = new Date();
+ System.out.println(dateFormat.format(date) + " " + text);
+ }
+
+ public static void msgError(final String text) {
+ msg("[Error] " + text);
+ }
+
+ class ResourceNameComparator implements Comparator<Resource> {
+ @Override
+ public int compare(Resource lhs, Resource rhs) {
+ return (lhs.getName().compareToIgnoreCase(rhs.getName()));
+ }
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/BinarySwitch.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/BinarySwitch.java
new file mode 100644
index 0000000..e3a580c
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/BinarySwitch.java
@@ -0,0 +1,86 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2017 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * BinarySwitch
+ *
+ * This class is used by IotivityClient to create an object representation of a remote binary switch service
+ * and update the values depending on the server response
+ */
+public class BinarySwitch extends Service {
+
+ public static final String OIC_TYPE_BINARY_SWITCH = "oic.r.switch.binary";
+ public static final String OCF_OIC_URI_PREFIX_BINARY_SWITCH = "/ocf/switch/";
+ public static final String UPNP_OIC_URI_PREFIX_BINARY_SWITCH = "/upnp/switch/";
+
+ public static final String VALUE_KEY = "value";
+ public static final boolean DEFAULT_VALUE = false;
+
+ private boolean mValue;
+ private boolean mIsInitialized;
+
+ public BinarySwitch() {
+ super();
+ mValue = DEFAULT_VALUE;
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) throws OcException {
+ super.setOcRepresentation(rep);
+ if (rep.hasAttribute(VALUE_KEY)) {
+ Object obj = rep.getValue(VALUE_KEY);
+ if (obj instanceof Boolean) {
+ mValue = (Boolean) obj;
+ mIsInitialized = true;
+ }
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() throws OcException {
+ OcRepresentation rep = super.getOcRepresentation();
+ rep.setValue(VALUE_KEY, mValue);
+ return rep;
+ }
+
+ public boolean getValue() {
+ return mValue;
+ }
+
+ public void setValue(boolean value) {
+ mValue = value;
+ }
+
+ public boolean isInitialized() {
+ return mIsInitialized;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + super.toString() +
+ ", " + "initialized: " + mIsInitialized +
+ ", " + VALUE_KEY + ": " + mValue + "]";
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Brightness.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Brightness.java
new file mode 100644
index 0000000..97b244b
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Brightness.java
@@ -0,0 +1,86 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2017 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Brightness
+ *
+ * This class is used by IotivityClient to create an object representation of a remote brightness service
+ * and update the values depending on the server response
+ */
+public class Brightness extends Service {
+
+ public static final String OIC_TYPE_BRIGHTNESS = "oic.r.light.brightness";
+ public static final String OCF_OIC_URI_PREFIX_BRIGHTNESS = "/ocf/brightness/";
+ public static final String UPNP_OIC_URI_PREFIX_BRIGHTNESS = "/upnp/brightness/";
+
+ public static final String BRIGHTNESS_KEY = "brightness";
+ public static final int DEFAULT_BRIGHTNESS = 100;
+
+ private int mBrightness;
+ private boolean mIsInitialized;
+
+ public Brightness() {
+ super();
+ mBrightness = DEFAULT_BRIGHTNESS;
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) throws OcException {
+ super.setOcRepresentation(rep);
+ if (rep.hasAttribute(BRIGHTNESS_KEY)) {
+ Object obj = rep.getValue(BRIGHTNESS_KEY);
+ if (obj instanceof Integer) {
+ mBrightness = (Integer) obj;
+ mIsInitialized = true;
+ }
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() throws OcException {
+ OcRepresentation rep = super.getOcRepresentation();
+ rep.setValue(BRIGHTNESS_KEY, mBrightness);
+ return rep;
+ }
+
+ public int getBrightness() {
+ return mBrightness;
+ }
+
+ public void setBrightness(int brightness) {
+ mBrightness = brightness;
+ }
+
+ public boolean isInitialized() {
+ return mIsInitialized;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + super.toString() +
+ ", " + "initialized: " + mIsInitialized +
+ ", " + BRIGHTNESS_KEY + ": " + mBrightness + "]";
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Configuration.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Configuration.java
new file mode 100644
index 0000000..ac7cdb7
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Configuration.java
@@ -0,0 +1,84 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2017 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Configuration
+ *
+ * This class is used by IotivityClient to create an object representation of a remote configuration service
+ * and update the values depending on the server response
+ */
+public class Configuration extends Service {
+
+ public static final String OIC_TYPE_CONFIG = "oic.wk.con";
+ public static final String OCF_OIC_URI_PREFIX_CONFIG = "/ocf/light-config/"; // TODO: regex match "/ocf/.*-config/"
+
+ public static final String NAME_KEY = "n";
+
+ private String mName;
+ private boolean mIsInitialized;
+
+ public Configuration() {
+ super();
+ mName = "";
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) throws OcException {
+ super.setOcRepresentation(rep);
+ if (rep.hasAttribute(NAME_KEY)) {
+ Object obj = rep.getValue(NAME_KEY);
+ if (obj instanceof String) {
+ mName = (String) obj;
+ mIsInitialized = true;
+ }
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() throws OcException {
+ OcRepresentation rep = super.getOcRepresentation();
+ rep.setValue(NAME_KEY, mName);
+ return rep;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public void setName(String name) {
+ mName = name;
+ }
+
+ public boolean isInitialized() {
+ return mIsInitialized;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + super.toString() +
+ ", " + "initialized: " + mIsInitialized +
+ ", " + NAME_KEY + ": " + mName + "]";
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/ConnectedThing.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/ConnectedThing.java
new file mode 100644
index 0000000..a8b4109
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/ConnectedThing.java
@@ -0,0 +1,163 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import com.amazonaws.services.iot.client.AWSIotDevice;
+import com.amazonaws.services.iot.client.AWSIotDeviceProperty;
+
+/**
+ * This class encapsulates an actual device. It extends {@link AWSIotDevice} to
+ * define properties that are to be kept in sync with the AWS IoT shadow.
+ */
+public class ConnectedThing extends AWSIotDevice {
+
+ static private IotivityClient iotivityClient;
+
+ @AWSIotDeviceProperty
+ private LightDevice[] lightDevices = new LightDevice[0];
+
+// @AWSIotDeviceProperty
+ private int lightState; // global light state
+
+ public ConnectedThing(String thingName, IotivityClient iotivityClient) {
+ super(thingName);
+ ConnectedThing.iotivityClient = iotivityClient;
+ }
+
+ public int getLightState() {
+ // 1. read the light state from the light actuator
+ int reportedState = lightState;
+// AlexaIotivityBridgeDemo.msg(">>> reported lightState: " + (reportedState != 0 ? "on" : "off"));
+
+ // 2. return the current light state
+ return reportedState;
+ }
+
+ public void setLightState(int desiredState) {
+ // 1. update the light actuator with the desired state
+ lightState = desiredState;
+ AlexaIotivityBridgeDemo.msg("<<< desired lightState to " + (desiredState != 0 ? "on" : "off"));
+
+ // 2. tell the iotivity client to update iotivity resources
+ for (LightDevice lightDevice : lightDevices) {
+ lightDevice.setPowerOn(desiredState != 0);
+ iotivityClient.updateLight(lightDevice.getName(), desiredState != 0, lightDevice.getBrightness());
+ }
+ }
+
+ public LightDevice[] getLightDevices() {
+ LightDevice[] reportedLightDevices = lightDevices;
+// AlexaIotivityBridgeDemo.msg(">>> reported light devices length = " + reportedLightDevices.length);
+ return reportedLightDevices;
+ }
+
+ public void setLightDevices(LightDevice[] desiredLightDevices) {
+ if (desiredLightDevices != null) {
+ lightDevices = desiredLightDevices;
+// AlexaIotivityBridgeDemo.msg(">>> desired light devices length = " + desiredLightDevices.length);
+ }
+ }
+
+ static public class LightDevice {
+
+ @AWSIotDeviceProperty
+ private String uri = "";
+
+ @AWSIotDeviceProperty
+ private String name = "";
+
+ @AWSIotDeviceProperty
+ private boolean powerOn;
+
+ @AWSIotDeviceProperty
+ private int brightness = -1; // uninitialized
+
+ public String getUri() {
+ String reportedUri = uri;
+// AlexaIotivityBridgeDemo.msg(">>> reported uri: " + reportedUri);
+ return reportedUri;
+ }
+
+ public void setUri(String desiredUri) {
+ uri = desiredUri;
+ AlexaIotivityBridgeDemo.msg("<<< desired uri: " + desiredUri);
+ }
+
+ public String getName() {
+ String reportedName = name;
+
+ // fake for changed upnp device name
+ if (NamesPropertyFile.getInstance().hasUri(uri)) {
+ reportedName = NamesPropertyFile.getInstance().getNameForUri(uri);
+ }
+
+// AlexaIotivityBridgeDemo.msg(">>> reported name: " + reportedName);
+ return reportedName;
+ }
+
+ public void setName(String desiredName) {
+ if (!name.equals(desiredName)) {
+ name = desiredName;
+ AlexaIotivityBridgeDemo.msg("<<< desired name: " + desiredName);
+
+ // update names property file
+ NamesPropertyFile.getInstance().updateNamesProperty(uri, name);
+ iotivityClient.updateLight(uri, name);
+ }
+ }
+
+ public boolean getPowerOn() {
+ boolean reportedPowerOn = powerOn;
+// AlexaIotivityBridgeDemo.msg(">>> reported powerOn: " + reportedPowerOn);
+ return reportedPowerOn;
+ }
+
+ public void setPowerOn(boolean desiredPowerOn) {
+ if (powerOn != desiredPowerOn) {
+ powerOn = desiredPowerOn;
+
+ AlexaIotivityBridgeDemo.msg("<<< desired powerOn: " + desiredPowerOn);
+
+ if (brightness >= 0) {
+ iotivityClient.updateLight(uri, powerOn, brightness);
+ }
+ }
+ }
+
+ public int getBrightness() {
+ int reportedBrightness = brightness;
+// AlexaIotivityBridgeDemo.msg(">>> reported brightness: " + reportedBrightness);
+ return reportedBrightness;
+ }
+
+ public void setBrightness(int desiredBrightness) {
+ if (brightness != desiredBrightness) {
+ brightness = desiredBrightness;
+
+ AlexaIotivityBridgeDemo.msg("<<< desired brightness: " + brightness);
+
+ iotivityClient.updateLight(uri, powerOn, brightness);
+ }
+ }
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Device.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Device.java
new file mode 100644
index 0000000..e283822
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Device.java
@@ -0,0 +1,227 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2016 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Device
+ *
+ * This class is used by IotivityClient to create an object representation of a remote device
+ * and update the values depending on the server response
+ */
+abstract public class Device extends Resource {
+
+ public static final String MANUFACTURER_KEY = "manufacturer";
+ public static final String MANUFACTURER_URL_KEY = "manufacturer_url";
+ public static final String MODEL_DESC_KEY = "model_description";
+ public static final String MODEL_NAME_KEY = "model_name";
+ public static final String MODEL_NUMBER_KEY = "model_number";
+ public static final String MODEL_URL_KEY = "model_url";
+ public static final String SERIAL_NUMBER_KEY = "serial_number";
+ public static final String PRESENTATION_URL_KEY = "presentation_url";
+ public static final String UPC_KEY = "upc";
+
+ public static final String LINKS_KEY = "links";
+
+ private String mManufacturer;
+ private String mManufacturerUrl;
+ private String mModelDescription;
+ private String mModelName;
+ private String mModelNumber;
+ private String mModelUrl;
+ private String mSerialNumber;
+ private String mPresentationUrl;
+ private String mUpc;
+
+ private Links mLinks;
+ private boolean mHasLinksProperty;
+
+ public Device() {
+ super();
+
+ mManufacturer = "";
+ mManufacturerUrl = "";
+ mModelDescription = "";
+ mModelName = "";
+ mModelNumber = "";
+ mModelUrl = "";
+ mSerialNumber = "";
+ mPresentationUrl = "";
+ mUpc = "";
+ mLinks = new Links();
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) throws OcException {
+ super.setOcRepresentation(rep);
+
+ if (rep.hasAttribute(MANUFACTURER_KEY)) {
+ mManufacturer = rep.getValue(MANUFACTURER_KEY);
+ }
+ if (rep.hasAttribute(MANUFACTURER_URL_KEY)) {
+ mManufacturerUrl = rep.getValue(MANUFACTURER_URL_KEY);
+ }
+ if (rep.hasAttribute(MODEL_DESC_KEY)) {
+ mModelDescription = rep.getValue(MODEL_DESC_KEY);
+ }
+ if (rep.hasAttribute(MODEL_NAME_KEY)) {
+ mModelName = rep.getValue(MODEL_NAME_KEY);
+ }
+ if (rep.hasAttribute(MODEL_NUMBER_KEY)) {
+ mModelNumber = rep.getValue(MODEL_NUMBER_KEY);
+ }
+ if (rep.hasAttribute(MODEL_URL_KEY)) {
+ mModelUrl = rep.getValue(MODEL_URL_KEY);
+ }
+ if (rep.hasAttribute(SERIAL_NUMBER_KEY)) {
+ mSerialNumber = rep.getValue(SERIAL_NUMBER_KEY);
+ }
+ if (rep.hasAttribute(PRESENTATION_URL_KEY)) {
+ mPresentationUrl = rep.getValue(PRESENTATION_URL_KEY);
+ }
+ if (rep.hasAttribute(UPC_KEY)) {
+ mUpc = rep.getValue(UPC_KEY);
+ }
+ if (rep.hasAttribute(LINKS_KEY)) {
+ OcRepresentation[] links = rep.getValue(LINKS_KEY);
+ mLinks.setOcRepresentation(links);
+ mHasLinksProperty = true;
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() throws OcException {
+ OcRepresentation rep = super.getOcRepresentation();
+
+ rep.setValue(MANUFACTURER_KEY, mManufacturer);
+ rep.setValue(MANUFACTURER_URL_KEY, mManufacturerUrl);
+ rep.setValue(MODEL_DESC_KEY, mModelDescription);
+ rep.setValue(MODEL_NAME_KEY, mModelName);
+ rep.setValue(MODEL_NUMBER_KEY, mModelNumber);
+ rep.setValue(MODEL_URL_KEY, mModelUrl);
+ rep.setValue(SERIAL_NUMBER_KEY, mSerialNumber);
+ rep.setValue(PRESENTATION_URL_KEY, mPresentationUrl);
+ rep.setValue(UPC_KEY, mUpc);
+
+ OcRepresentation[] links = mLinks.getOcRepresentation();
+ if ((links != null) && (links.length > 0)) {
+ rep.setValue(LINKS_KEY, links);
+ }
+
+ return rep;
+ }
+
+ public String getManufacturer() {
+ return mManufacturer;
+ }
+
+ public void setManufacturer(String manufacturer) {
+ mManufacturer = manufacturer;
+ }
+
+ public String getManufacturerUrl() {
+ return mManufacturerUrl;
+ }
+
+ public void setManufacturerUrl(String manufacturerUrl) {
+ mManufacturerUrl = manufacturerUrl;
+ }
+
+ public String getModelDescription() {
+ return mModelDescription;
+ }
+
+ public void setModelDescription(String modelDescription) {
+ mModelDescription = modelDescription;
+ }
+
+ public String getModelName() {
+ return mModelName;
+ }
+
+ public void setModelName(String modelName) {
+ mModelName = modelName;
+ }
+
+ public String getModelNumber() {
+ return mModelNumber;
+ }
+
+ public void setModelNumber(String modelNumber) {
+ mModelNumber = modelNumber;
+ }
+
+ public String getModelUrl() {
+ return mModelUrl;
+ }
+
+ public void setModelUrl(String modelUrl) {
+ mModelUrl = modelUrl;
+ }
+
+ public String getSerialNumber() {
+ return mSerialNumber;
+ }
+
+ public void setSerialNumber(String serialNumber) {
+ mSerialNumber = serialNumber;
+ }
+
+ public String getPresentationUrl() {
+ return mPresentationUrl;
+ }
+
+ public void setPresentationUrl(String presentationUrl) {
+ mPresentationUrl = presentationUrl;
+ }
+
+ public String getUpc() {
+ return mUpc;
+ }
+
+ public void setUpc(String upc) {
+ mUpc = upc;
+ }
+
+ public boolean hasLinksProperty() {
+ return mHasLinksProperty;
+ }
+
+ public Links getLinks() {
+ return mLinks;
+ }
+
+ public void setLinks(Links links) {
+ mLinks = (links != null) ? links : new Links();
+ }
+
+ @Override
+ public String toString() {
+ return "[" + super.toString() + ", " + MANUFACTURER_KEY + ": " + mManufacturer + ", " + MANUFACTURER_URL_KEY
+ + ": " + mManufacturerUrl + ", " + MODEL_NAME_KEY + ": " + mModelName + ", " + MODEL_NUMBER_KEY + ": "
+ + mModelNumber + ", " + MODEL_URL_KEY + ": " + mModelUrl + ", " + MODEL_DESC_KEY + ": "
+ + mModelDescription + ", " + SERIAL_NUMBER_KEY + ": " + mSerialNumber + ", " + PRESENTATION_URL_KEY
+ + ": " + mPresentationUrl + ", " + UPC_KEY + ": " + mUpc + ", " + "hasLinksProp: " + mHasLinksProperty
+ + ", " + LINKS_KEY + mLinks + "]";
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityClient.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityClient.java
new file mode 100644
index 0000000..00d57ae
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityClient.java
@@ -0,0 +1,894 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.ErrorCode;
+import org.iotivity.base.ObserveType;
+import org.iotivity.base.OcConnectivityType;
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcHeaderOption;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.OcRepresentation;
+import org.iotivity.base.OcResource;
+import org.iotivity.base.examples.ConnectedThing.LightDevice;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * IotivityClient
+ *
+ * IotivityClient provides interaction with the IoTivity client stack.
+ */
+public class IotivityClient implements
+ OcPlatform.OnResourceFoundListener,
+ OcPlatform.OnResourcesFoundListener,
+ OcResource.OnGetListener,
+ OcResource.OnPutListener,
+ OcResource.OnPostListener,
+ OcResource.OnObserveListener {
+
+ private final Map<String, OcResource> mIotivityResourceLookup = new ConcurrentHashMap<>();
+ private final Map<String, Resource> mResourceLookup = new ConcurrentHashMap<>();
+ private final Map<String, ConnectedThing.LightDevice> mConnectedThingLookup = new ConcurrentHashMap<>();
+ private final Map<String, Long> mStaleResourceUriLookup = new ConcurrentHashMap<>();
+ private final Comparator<ConnectedThing.LightDevice> nameComparator = new DeviceNameComparator();
+
+ private ConnectedThing mConnectedThing;
+
+ public IotivityClient() {
+ // Start running a task to collect stale resources (runs every 10 seconds)
+ Timer timer = new Timer();
+ timer.schedule(new StaleResourcePurgeTask(), 10*1000, 10*1000);
+ }
+
+ /**
+ * An event handler to be executed whenever a "findResource" request completes successfully
+ *
+ * @param ocResource found resource
+ */
+ @Override
+ public synchronized void onResourceFound(OcResource ocResource) {
+ if (null == ocResource) {
+ AlexaIotivityBridgeDemo.msgError("Found resource is invalid");
+ return;
+ }
+
+ // Get the resource uri
+ String resourceUri = ocResource.getUri();
+ // Get the resource host address
+ String hostAddress = ocResource.getHost();
+
+ boolean tracked = false;
+
+ // For now, we are only interested in known light resources
+ if (resourceUri.startsWith(Light.UPNP_OIC_URI_PREFIX_LIGHT)
+ || resourceUri.startsWith(Light.OCF_OIC_URI_PREFIX_LIGHT)
+ || resourceUri.startsWith(Light.OIC_URI_PREFIX_LIGHT)) {
+ if (!mResourceLookup.containsKey(resourceUri)) {
+
+ AlexaIotivityBridgeDemo.msg("URI of the new light resource: " + resourceUri);
+// AlexaIotivityBridgeDemo.msg("Host address of the new light resource: " + hostAddress);
+
+ Light light = new Light();
+ light.setUri(resourceUri);
+
+ mResourceLookup.put(resourceUri, light);
+ }
+
+ // Call a local method which will internally invoke "observe" API on the found resource
+ observeFoundResource(ocResource);
+
+ // For OCF devices, the name is the 'n' property of the device
+ if (resourceUri.startsWith(Light.OCF_OIC_URI_PREFIX_LIGHT)
+ || resourceUri.startsWith(Light.OIC_URI_PREFIX_LIGHT)) {
+ Light light = (Light) mResourceLookup.get(resourceUri);
+ OcPlatform.OnDeviceFoundListener deviceFoundListener = new DeviceFoundListener(light);
+ try {
+ OcPlatform.getDeviceInfo(hostAddress, OcPlatform.WELL_KNOWN_DEVICE_QUERY,
+ EnumSet.of(OcConnectivityType.CT_DEFAULT), deviceFoundListener);
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError(e.toString());
+ }
+ }
+
+ mIotivityResourceLookup.put(resourceUri, ocResource);
+ tracked = true;
+
+ } else {
+ AlexaIotivityBridgeDemo.msg("URI of the new (for now, untracked) resource: " + resourceUri);
+ }
+
+ if (tracked) {
+ // Call a local method which will internally invoke "get" API on the found resource
+ getResourceRepresentation(ocResource);
+ }
+ }
+
+ @Override
+ public synchronized void onFindResourceFailed(Throwable throwable, String uri) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ AlexaIotivityBridgeDemo.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ AlexaIotivityBridgeDemo.msgError("Uri: " + uri + " Error code: " + errCode);
+ }
+
+ AlexaIotivityBridgeDemo.msgError("Find resource failed");
+ }
+
+ /**
+ * Resource found listener specifically for links.
+ */
+ class ResourceFoundListener implements OcPlatform.OnResourceFoundListener {
+
+ private String mParentUri;
+ private String mHref; // expected link uri
+
+ ResourceFoundListener(String resourceUri, String href) {
+ mParentUri = resourceUri;
+ mHref = href;
+ }
+
+ public synchronized void onResourceFound(OcResource ocResource) {
+ if (null == ocResource) {
+ AlexaIotivityBridgeDemo.msgError("Found resource is invalid");
+ return;
+ }
+
+ String resourceUri = ocResource.getUri();
+
+ boolean tracked = false;
+
+ if (resourceUri.equalsIgnoreCase(mHref)) {
+ if (!mResourceLookup.containsKey(resourceUri)) {
+ AlexaIotivityBridgeDemo.msg("URI of the new linked resource: " + resourceUri);
+
+ if (resourceUri.startsWith(BinarySwitch.UPNP_OIC_URI_PREFIX_BINARY_SWITCH)
+ || resourceUri.startsWith(BinarySwitch.OCF_OIC_URI_PREFIX_BINARY_SWITCH)) {
+ BinarySwitch binarySwitch = new BinarySwitch();
+ binarySwitch.setUri(resourceUri);
+
+ // Update the device
+ Light light = (Light) mResourceLookup.get(mParentUri);
+ if (light != null) {
+ light.setBinarySwitch(binarySwitch);
+ mResourceLookup.put(resourceUri, binarySwitch);
+ tracked = true;
+ }
+
+ } else if (resourceUri.startsWith(Brightness.UPNP_OIC_URI_PREFIX_BRIGHTNESS)
+ || resourceUri.startsWith(Brightness.OCF_OIC_URI_PREFIX_BRIGHTNESS)) {
+ Brightness brightness = new Brightness();
+ brightness.setUri(resourceUri);
+
+ // Update the device
+ Light light = (Light) mResourceLookup.get(mParentUri);
+ if (light != null) {
+ light.setBrightness(brightness);
+ mResourceLookup.put(resourceUri, brightness);
+ tracked = true;
+ }
+
+ } else if (resourceUri.startsWith(Configuration.OCF_OIC_URI_PREFIX_CONFIG)) {
+ Configuration config = new Configuration();
+ config.setUri(resourceUri);
+
+ // Update the device
+ Light light = (Light) mResourceLookup.get(mParentUri);
+ if (light != null) {
+ light.setConfiguration(config);
+ mResourceLookup.put(resourceUri, config);
+ tracked = true;
+ }
+
+ } else {
+ // Unexpected resource
+ AlexaIotivityBridgeDemo.msg("URI of an unexpected resource: " + resourceUri);
+ }
+
+ mIotivityResourceLookup.put(resourceUri, ocResource);
+
+ if (tracked) {
+ // Call a local method which will internally invoke "get" API on the found resource
+ getResourceRepresentation(ocResource);
+
+ // Call a local method which will internally invoke "observe" API on the found resource
+ observeFoundResource(ocResource);
+ }
+ }
+ }
+ }
+
+ public synchronized void onFindResourceFailed(Throwable throwable, String uri) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ AlexaIotivityBridgeDemo.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ AlexaIotivityBridgeDemo.msgError("Uri: " + uri + " Error code: " + errCode);
+ }
+
+ AlexaIotivityBridgeDemo.msgError("Find resource failed");
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "findResources" request
+ * completes successfully
+ *
+ * @param ocResources
+ * array of found resources
+ */
+ @Override
+ public synchronized void onResourcesFound(OcResource[] ocResources) {
+ if (null == ocResources) {
+ AlexaIotivityBridgeDemo.msgError("Found resources is invalid");
+ return;
+ }
+
+ for (OcResource ocResource : ocResources) {
+ onResourceFound(ocResource);
+ }
+ }
+
+ @Override
+ public synchronized void onFindResourcesFailed(Throwable throwable, String uri) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ AlexaIotivityBridgeDemo.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ AlexaIotivityBridgeDemo.msgError("Uri: " + uri + " Error code: " + errCode);
+ }
+
+ AlexaIotivityBridgeDemo.msgError("Find resource failed");
+ }
+
+ /**
+ * Local method to get representation of a found resource
+ *
+ * @param ocResource found resource
+ */
+ private void getResourceRepresentation(OcResource ocResource) {
+
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "get" API with a OcResource.OnGetListener event listener implementation
+ ocResource.get(queryParams, this);
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Error occurred while invoking \"get\" API -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "get" request completes successfully
+ *
+ * @param list list of the header options
+ * @param ocRepresentation representation of a resource
+ */
+ @Override
+ public synchronized void onGetCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation) {
+
+ try {
+ // Read attribute values into local representation of resource
+ final String ocRepUri = ocRepresentation.getUri();
+ if (ocRepUri != null && !ocRepUri.isEmpty()) {
+// AlexaIotivityBridgeDemo.msg("Get Resource URI: " + ocRepUri);
+
+ Resource resource = mResourceLookup.get(ocRepUri);
+ if (resource != null) {
+ resource.setOcRepresentation(ocRepresentation);
+// AlexaIotivityBridgeDemo.msg("Get Resource attributes: " + resource.toString());
+
+ if (resource instanceof Device) {
+ Device device = (Device) resource;
+ Links links = device.getLinks();
+ for (Link link : links.getLinks()) {
+ String href = link.getHref();
+ // rt could be String or String[]
+ Object rt = link.getRt();
+ String rtAsString = null;
+ if (rt instanceof String) {
+ rtAsString = (String) rt;
+
+ } else if (rt instanceof String[]) {
+ if (((String[]) rt).length > 0) {
+ rtAsString = ((String[]) rt)[0];
+ } else {
+ AlexaIotivityBridgeDemo.msgError("(String[])rt is empty");
+ }
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("Unknown rt type of " + rt.getClass().getName());
+ }
+
+ if ((rtAsString != null) && (!mResourceLookup.containsKey(href))) {
+ AlexaIotivityBridgeDemo.msg("Finding all resources of type " + rtAsString);
+ String requestUri = OcPlatform.WELL_KNOWN_QUERY + "?rt=" + rtAsString;
+ OcPlatform.findResource("", requestUri, EnumSet.of(OcConnectivityType.CT_DEFAULT), new ResourceFoundListener(ocRepUri, href));
+ }
+ }
+
+ if (resource instanceof Light) {
+ Light light = (Light) resource;
+
+ if (((light.getBinarySwitch() != null) && (light.getBinarySwitch().isInitialized())
+ && (light.getBrightness() != null) && light.getBrightness().isInitialized())
+ || (!light.hasLinksProperty())) {
+
+ ConnectedThing.LightDevice lightDevice = mConnectedThingLookup.get(light.getUri());
+ if (lightDevice == null) {
+ lightDevice = new ConnectedThing.LightDevice();
+ lightDevice.setUri(light.getUri());
+ }
+ lightDevice.setName(light.getName());
+ lightDevice.setPowerOn(light.getState());
+ lightDevice.setBrightness(light.getLightLevel());
+ mConnectedThingLookup.put(light.getUri(), lightDevice);
+ mStaleResourceUriLookup.put(light.getUri(), System.currentTimeMillis());
+
+ // publish updates to connected thing
+ ConnectedThing.LightDevice[] lightDevices = mConnectedThingLookup.values().toArray(new ConnectedThing.LightDevice[0]);
+ Arrays.sort(lightDevices, nameComparator);
+ mConnectedThing.setLightDevices(lightDevices);
+// AlexaIotivityBridgeDemo.publishUpdatePayload(toUpdatePayload(lightDevices));
+ }
+
+ } else {
+ // TODO: handle additional devices
+ }
+ }
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("Get No resource for uri " + ocRepUri);
+ }
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("Get No Resource URI");
+ }
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Get Failed to read the attributes of resource -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "get" request fails
+ *
+ * @param throwable exception
+ */
+ @Override
+ public synchronized void onGetFailed(Throwable throwable) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ AlexaIotivityBridgeDemo.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ AlexaIotivityBridgeDemo.msgError("Error code: " + errCode);
+ }
+ AlexaIotivityBridgeDemo.msgError("Failed to get representation of a found light resource");
+ }
+
+ /**
+ * Set state for a light resource
+ */
+ public void updateLight(String uri, boolean newState, int newLightLevel) {
+ ConnectedThing.LightDevice lightDevice = mConnectedThingLookup.get(uri);
+ if (lightDevice != null) {
+ OcResource ocResource = mIotivityResourceLookup.get(uri);
+ if (ocResource != null) {
+ putLightRepresentation(ocResource, newState, newLightLevel);
+ }
+ }
+ }
+
+ /**
+ * Rename a light resource
+ */
+ public void updateLight(String uri, String newName) {
+ ConnectedThing.LightDevice lightDevice = mConnectedThingLookup.get(uri);
+ if (lightDevice != null) {
+ OcResource ocResource = mIotivityResourceLookup.get(uri);
+ if (ocResource != null) {
+ putLightRepresentation(ocResource, newName);
+ }
+ }
+ }
+
+ /**
+ * Local method to put a different name for this light resource
+ */
+ private void putLightRepresentation(OcResource ocResource, String newName) {
+ final String resourceUri = ocResource.getUri();
+
+ Light light = (Light) mResourceLookup.get(resourceUri);
+ if (light != null && resourceUri.startsWith(Light.OCF_OIC_URI_PREFIX_LIGHT)) {
+ if (light.hasLinksProperty()) {
+ final Configuration config = light.getConfiguration();
+ if ((config != null) && (config.isInitialized())) {
+ config.setName(newName);
+ OcRepresentation configRepresentation = null;
+ try {
+ configRepresentation = config.getOcRepresentation();
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Failed to get OcRepresentation from a configuration -- " + e.toString());
+ }
+
+ if (configRepresentation != null) {
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "put" API with a new representation
+ OcResource configResource = mIotivityResourceLookup.get(config.getUri());
+ if (configResource != null) {
+ configResource.put(configRepresentation, queryParams, this);
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("No configuration for light uri " + resourceUri);
+ }
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Error occurred while invoking \"put\" API -- " + e.toString());
+ }
+ }
+
+ } else {
+ if (config == null) {
+ AlexaIotivityBridgeDemo.msgError("No configuration for light uri " + resourceUri);
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("No configuration (initialized) for light uri " + resourceUri);
+ }
+ }
+
+ } else {
+ // properties are on the device
+ light.setName(newName);
+
+ OcRepresentation lightRepresentation = null;
+ try {
+ lightRepresentation = light.getOcRepresentation();
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Failed to get OcRepresentation from light -- " + e.toString());
+ }
+
+ if (lightRepresentation != null) {
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "put" API with a new representation
+ ocResource.put(lightRepresentation, queryParams, this);
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Error occurred while invoking \"put\" API -- " + e.toString());
+ }
+ }
+ }
+
+ } else if (!resourceUri.startsWith(Light.OCF_OIC_URI_PREFIX_LIGHT)) {
+// AlexaIotivityBridgeDemo.msg("No configuration available for light uri " + resourceUri);
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("No light for uri " + resourceUri);
+ }
+ }
+
+ /**
+ * Local method to put a different state for this light resource
+ */
+ private void putLightRepresentation(OcResource ocResource, boolean newState, int newLightLevel) {
+ final String resourceUri = ocResource.getUri();
+
+ Light light = (Light) mResourceLookup.get(resourceUri);
+ if (light != null) {
+ // set new values
+ if (light.hasLinksProperty()) {
+ // actually, set directly on the service (avoid possible conflict if auto discover is running)
+ // light.setState(newState);
+ // light.setLightLevel(newLightLevel);
+
+ final BinarySwitch binarySwitch = light.getBinarySwitch();
+ if ((binarySwitch != null) && (binarySwitch.isInitialized())) {
+ binarySwitch.setValue(newState);
+ OcRepresentation binarySwitchRepresentation = null;
+ try {
+ binarySwitchRepresentation = binarySwitch.getOcRepresentation();
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Failed to get OcRepresentation from a binary switch -- " + e.toString());
+ }
+
+ if (binarySwitchRepresentation != null) {
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "put" (or "post") API with a new representation
+ OcResource binarySwitchResource = mIotivityResourceLookup.get(binarySwitch.getUri());
+ if (binarySwitchResource != null) {
+ if (binarySwitchResource.getUri().startsWith(BinarySwitch.UPNP_OIC_URI_PREFIX_BINARY_SWITCH)) {
+ // upnp bridge requires 'post'
+ binarySwitchResource.post(binarySwitchRepresentation, queryParams, this);
+ } else {
+ binarySwitchResource.put(binarySwitchRepresentation, queryParams, this);
+ }
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("No binary switch for light uri " + resourceUri);
+ }
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Error occurred while invoking \"put\" API -- " + e.toString());
+ }
+ }
+
+ } else {
+ if (binarySwitch == null) {
+ AlexaIotivityBridgeDemo.msgError("No binary switch for light uri " + resourceUri);
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("No binary switch (initialized) for light uri " + resourceUri);
+ }
+ }
+
+ Brightness brightness = light.getBrightness();
+ if ((brightness != null) && (brightness.isInitialized())) {
+ brightness.setBrightness(newLightLevel);
+ OcRepresentation brightnessRepresentation = null;
+ try {
+ brightnessRepresentation = brightness.getOcRepresentation();
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Failed to get OcRepresentation from a brightness -- " + e.toString());
+ }
+
+ if (brightnessRepresentation != null) {
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "put" (or "post") API with a new representation
+ OcResource brightnessResource = mIotivityResourceLookup.get(brightness.getUri());
+ if (brightnessResource != null) {
+ if (brightnessResource.getUri().startsWith(Brightness.UPNP_OIC_URI_PREFIX_BRIGHTNESS)) {
+ // upnp bridge requires 'post'
+ brightnessResource.post(brightnessRepresentation, queryParams, this);
+ } else {
+ brightnessResource.put(brightnessRepresentation, queryParams, this);
+ }
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("No brightness for light uri " + resourceUri);
+ }
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Error occurred while invoking \"put\" API -- " + e.toString());
+ }
+ }
+
+ } else {
+ if (brightness == null) {
+ AlexaIotivityBridgeDemo.msgError("No brightness for light uri " + resourceUri);
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("No brightness (initialized) for light uri " + resourceUri);
+ }
+ }
+
+ } else {
+ // properties are on the device
+ light.setState(newState);
+ light.setLightLevel(newLightLevel);
+
+ OcRepresentation lightRepresentation = null;
+ try {
+ lightRepresentation = light.getOcRepresentation();
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Failed to get OcRepresentation from light -- " + e.toString());
+ }
+
+ if (lightRepresentation != null) {
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "put" API with a new representation
+ ocResource.put(lightRepresentation, queryParams, this);
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Error occurred while invoking \"put\" API -- " + e.toString());
+ }
+ }
+ }
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("No light for uri " + resourceUri);
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "put" request completes successfully
+ *
+ * @param list list of the header options
+ * @param ocRepresentation representation of a resource
+ */
+ @Override
+ public synchronized void onPutCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation) {
+
+ try {
+ // Read attribute values into local representation of resource
+ final String ocRepUri = ocRepresentation.getUri();
+ if (ocRepUri != null && !ocRepUri.isEmpty()) {
+// AlexaIotivityBridgeDemo.msg("Put Resource URI: " + ocRepUri);
+
+ Resource resource = mResourceLookup.get(ocRepUri);
+ if (resource != null) {
+ resource.setOcRepresentation(ocRepresentation);
+ AlexaIotivityBridgeDemo.msg("Put Resource attributes: " + resource.toString());
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("Put No resource for uri " + ocRepUri);
+ }
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("Put No Resource URI");
+ }
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Put Failed to create resource representation -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "put" request fails
+ *
+ * @param throwable exception
+ */
+ @Override
+ public synchronized void onPutFailed(Throwable throwable) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ AlexaIotivityBridgeDemo.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ AlexaIotivityBridgeDemo.msgError("Error code: " + errCode);
+ }
+ AlexaIotivityBridgeDemo.msgError("Failed to \"put\" a new representation");
+ }
+
+ /**
+ * An event handler to be executed whenever a "post" request completes successfully
+ *
+ * @param list list of the header options
+ * @param ocRepresentation representation of a resource
+ */
+ @Override
+ public synchronized void onPostCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation) {
+
+ try {
+ // Read attribute values into local representation of resource
+ final String ocRepUri = ocRepresentation.getUri();
+ if (ocRepUri != null && !ocRepUri.isEmpty()) {
+// AlexaIotivityBridgeDemo.msg("Post Resource URI: " + ocRepUri);
+
+ Resource resource = mResourceLookup.get(ocRepUri);
+ if (resource != null) {
+ resource.setOcRepresentation(ocRepresentation);
+ AlexaIotivityBridgeDemo.msg("Post Resource attributes: " + resource.toString());
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("Post No resource for uri " + ocRepUri);
+ }
+
+ } else {
+ AlexaIotivityBridgeDemo.msgError("Post No Resource URI");
+ }
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Post Failed to create resource representation -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "post" request fails
+ *
+ * @param throwable exception
+ */
+ @Override
+ public synchronized void onPostFailed(Throwable throwable) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ AlexaIotivityBridgeDemo.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ AlexaIotivityBridgeDemo.msgError("Error code: " + errCode);
+ }
+ AlexaIotivityBridgeDemo.msgError("Failed to \"post\" a new representation");
+ }
+
+ /**
+ * Local method to start observing this resource
+ *
+ * @param ocResource found resource
+ */
+ private void observeFoundResource(OcResource ocResource) {
+ try {
+ // Invoke resource's "observe" API with a observe type
+ ocResource.observe(ObserveType.OBSERVE, new HashMap<String, String>(), this);
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Error occurred while invoking \"observe\" API -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "observe" request completes successfully
+ *
+ * @param list list of the header options
+ * @param ocRepresentation representation of a resource
+ * @param sequenceNumber sequence number
+ */
+ @Override
+ public synchronized void onObserveCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation, int sequenceNumber) {
+// if (OcResource.OnObserveListener.REGISTER == sequenceNumber) {
+// AlexaIotivityBridgeDemo.msg("Observe registration action is successful");
+// } else {
+// AlexaIotivityBridgeDemo.msg("Observe sequence number " + sequenceNumber);
+// }
+
+ if ((sequenceNumber > 0) && (sequenceNumber < (OcResource.OnObserveListener.MAX_SEQUENCE_NUMBER + 1))) {
+ onGetCompleted(list, ocRepresentation);
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "observe" request fails
+ *
+ * @param throwable exception
+ */
+ @Override
+ public synchronized void onObserveFailed(Throwable throwable) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ AlexaIotivityBridgeDemo.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ AlexaIotivityBridgeDemo.msgError("Error code: " + errCode);
+ }
+ AlexaIotivityBridgeDemo.msgError("Observation of the found light resource has failed");
+ }
+
+ public void setConnectedThing(ConnectedThing connectedThing) {
+ mConnectedThing = connectedThing;
+ }
+
+ private String toUpdatePayload(ConnectedThing.LightDevice[] lightDevices) {
+ StringBuffer payload = new StringBuffer();
+ payload.append("{\"state\":{\"reported\":{\"lightDevices\":[");
+
+ int index = 0;
+ for (LightDevice lightDevice : lightDevices) {
+ payload.append("{\"name\":\"" + lightDevice.getName() + "\",").
+ append("\"uri\":\"" + lightDevice.getUri() + "\",").
+ append("\"powerOn\":" + lightDevice.getPowerOn() + ",").
+ append("\"brightness\":" + lightDevice.getBrightness() + "}");
+
+ if (++index < lightDevices.length) {
+ payload.append(",");
+ }
+ }
+ payload.append("]}}}");
+ return payload.toString();
+ }
+
+ public synchronized void cancelObserve() {
+ for (OcResource ocResource : mIotivityResourceLookup.values()) {
+ if (ocResource.getUri().contains(Light.OIC_URI_PREFIX_LIGHT)) {
+ try {
+ ocResource.cancelObserve();
+ } catch (OcException e) {
+ IotivityScanner.msgError("Error occurred while invoking \"cancelObserve\" API for resource "
+ + ocResource.getUri() + " -- " + e.toString());
+ }
+ }
+ }
+ }
+
+ class DeviceFoundListener implements OcPlatform.OnDeviceFoundListener {
+
+ Light light;
+
+ public DeviceFoundListener(Light light) {
+ this.light = light;
+ }
+
+ @Override
+ public void onDeviceFound(OcRepresentation ocRepresentation) {
+ try {
+ if (ocRepresentation.hasAttribute("n")) {
+ String name = ocRepresentation.getValue("n");
+ light.setName(name);
+// AlexaIotivityBridgeDemo.msg("OCF device found callback: 'n' = " + name);
+ } else {
+ AlexaIotivityBridgeDemo.msgError("'n' attribute not found for device " + light.toString());
+ }
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Get 'n' attribute failed for device " + light.toString());
+ e.printStackTrace();
+ }
+ }
+ };
+
+ class DeviceNameComparator implements Comparator<ConnectedThing.LightDevice> {
+ @Override
+ public int compare(ConnectedThing.LightDevice lhs, ConnectedThing.LightDevice rhs) {
+ return (lhs.getName().compareToIgnoreCase(rhs.getName()));
+ }
+ }
+
+ public class StaleResourcePurgeTask extends TimerTask {
+ @Override
+ public void run() {
+ try {
+ boolean mustDeleteShadowDocument = false;
+ long now = System.currentTimeMillis();
+ for (Map.Entry<String,Long> entry : mStaleResourceUriLookup.entrySet()) {
+ if (entry.getValue() < now - 30*1000) {
+ // uri not seen in 30 seconds, remove from maps
+ String key = entry.getKey();
+ AlexaIotivityBridgeDemo.msg("Removing stale uri " + key);
+ Light light = (Light) mResourceLookup.get(key);
+ for (Link link : light.getLinks().getLinks()) {
+ AlexaIotivityBridgeDemo.msg("Removing stale uri link " + link.getHref());
+ mIotivityResourceLookup.remove(link.getHref());
+ mResourceLookup.remove(link.getHref());
+ }
+ mConnectedThingLookup.remove(key);
+ mIotivityResourceLookup.remove(key);
+ mResourceLookup.remove(key);
+ mStaleResourceUriLookup.remove(key);
+
+ mustDeleteShadowDocument = true;
+ }
+ }
+ if (mConnectedThingLookup.isEmpty()) {
+ mConnectedThing.setLightDevices(new ConnectedThing.LightDevice[0]);
+ mustDeleteShadowDocument = true;
+ }
+ if (mustDeleteShadowDocument) {
+ mConnectedThing.delete();
+ }
+
+ } catch (Exception e) {
+ AlexaIotivityBridgeDemo.msgError("Error running StaleResourcePurgeTask: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityScanner.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityScanner.java
new file mode 100644
index 0000000..1c2eac8
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityScanner.java
@@ -0,0 +1,123 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.ModeType;
+import org.iotivity.base.OcConnectivityType;
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.PlatformConfig;
+import org.iotivity.base.QualityOfService;
+import org.iotivity.base.ServiceType;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.EnumSet;
+
+/**
+ * IotivityScanner
+ */
+public class IotivityScanner {
+
+ private static IotivityScannerClient iotivityClient;
+
+ /**
+ * Configure and initialize platform.
+ */
+ private static void startIotivityClient(int frequency) {
+
+ PlatformConfig platformConfig = new PlatformConfig(
+ ServiceType.IN_PROC,
+ ModeType.CLIENT,
+ "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
+ 0, // Uses randomly available port
+ QualityOfService.LOW
+ );
+ msg("Configuring platform.");
+ OcPlatform.Configure(platformConfig);
+
+ iotivityClient = new IotivityScannerClient(frequency);
+ }
+
+ public static void main(String args[]) throws IOException, InterruptedException {
+
+ int frequency = 10; // seconds;
+
+ if (args.length > 0) {
+ try {
+ frequency = Integer.valueOf(args[0]);
+ } catch (NumberFormatException e) {
+ msg("Frequency must be an integer in the range (1, 60), using default 10.");
+ }
+
+ frequency = Math.max(1, frequency);
+ frequency = Math.min(60, frequency);
+ }
+
+ startIotivityClient(frequency); // creates iotivityClient
+
+ while (true) {
+ try {
+ msg("Finding all resources of type " + Light.OIC_TYPE_DEVICE_LIGHT);
+ String requestUri = OcPlatform.WELL_KNOWN_QUERY + "?rt=" + Light.OIC_TYPE_DEVICE_LIGHT;
+ OcPlatform.findResources("", requestUri, EnumSet.of(OcConnectivityType.CT_DEFAULT), iotivityClient);
+
+ } catch (OcException e) {
+ msgError(e.toString());
+ msgError("Failed to invoke find resource API");
+ }
+
+ sleep(frequency);
+
+ iotivityClient.cancelObserve();
+ }
+ }
+
+ private static void sleep(int seconds) {
+ try {
+ Thread.sleep(seconds * 1000);
+ } catch (InterruptedException e) {
+ msgError(e.toString());
+ }
+ }
+
+ public static void msg(final String text) {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
+ Date date = new Date();
+ System.out.println(dateFormat.format(date) + " " + text);
+ }
+
+ public static void msgError(final String text) {
+ msg("[Error] " + text);
+ }
+
+ class ResourceNameComparator implements Comparator<Resource> {
+ @Override
+ public int compare(Resource lhs, Resource rhs) {
+ return (lhs.getName().compareToIgnoreCase(rhs.getName()));
+ }
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityScannerClient.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityScannerClient.java
new file mode 100644
index 0000000..b824538
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/IotivityScannerClient.java
@@ -0,0 +1,810 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.ErrorCode;
+import org.iotivity.base.ObserveType;
+import org.iotivity.base.OcConnectivityType;
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcHeaderOption;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.OcRepresentation;
+import org.iotivity.base.OcResource;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * IotivityClient
+ *
+ * IotivityClient provides interaction with the IoTivity client stack.
+ */
+public class IotivityScannerClient implements
+ OcPlatform.OnResourceFoundListener,
+ OcPlatform.OnResourcesFoundListener,
+ OcResource.OnGetListener,
+ OcResource.OnPutListener,
+ OcResource.OnPostListener,
+ OcResource.OnObserveListener {
+
+ private final Map<String, OcResource> mIotivityResourceLookup = new ConcurrentHashMap<>();
+ private final Map<String, Resource> mResourceLookup = new ConcurrentHashMap<>();
+ private final Map<String, Long> mStaleResourceUriLookup = new ConcurrentHashMap<>();
+
+ public IotivityScannerClient(int frequency) {
+ // Start running a task to collect stale resources (runs every 10 seconds)
+ Timer timer = new Timer();
+ timer.schedule(new StaleResourcePurgeTask(frequency), 10 * 1000, 10 * 1000);
+ }
+
+ /**
+ * An event handler to be executed whenever a "findResource" request completes successfully
+ *
+ * @param ocResource found resource
+ */
+ @Override
+ public synchronized void onResourceFound(OcResource ocResource) {
+ if (null == ocResource) {
+ IotivityScanner.msgError("Found resource is invalid");
+ return;
+ }
+
+ // Get the resource uri
+ String resourceUri = ocResource.getUri();
+ // Get the resource host address
+ String hostAddress = ocResource.getHost();
+
+ boolean tracked = false;
+
+ // For now, we are only interested in known light resources
+ if (resourceUri.startsWith(Light.UPNP_OIC_URI_PREFIX_LIGHT)
+ || resourceUri.startsWith(Light.OCF_OIC_URI_PREFIX_LIGHT)) {
+ if (!mResourceLookup.containsKey(resourceUri)) {
+
+ IotivityScanner.msg("URI of the new light resource: " + resourceUri);
+// IotivityScanner.msg("Host address of the new light resource: " + hostAddress);
+
+ Light light = new Light();
+ light.setUri(resourceUri);
+
+ mResourceLookup.put(resourceUri, light);
+ }
+
+ // Call a local method which will internally invoke "observe" API on the found resource
+ observeFoundResource(ocResource);
+
+ // For OCF devices, the name is the 'n' property of the device
+ if (resourceUri.startsWith(Light.OCF_OIC_URI_PREFIX_LIGHT)) {
+ Light light = (Light) mResourceLookup.get(resourceUri);
+ OcPlatform.OnDeviceFoundListener deviceFoundListener = new DeviceFoundListener(light);
+ try {
+ OcPlatform.getDeviceInfo(hostAddress, OcPlatform.WELL_KNOWN_DEVICE_QUERY,
+ EnumSet.of(OcConnectivityType.CT_DEFAULT), deviceFoundListener);
+ } catch (OcException e) {
+ IotivityScanner.msgError(e.toString());
+ }
+ }
+
+ mIotivityResourceLookup.put(resourceUri, ocResource);
+ tracked = true;
+
+ } else {
+ IotivityScanner.msg("URI of the new (for now, untracked) resource: " + resourceUri);
+ }
+
+ if (tracked) {
+ // Call a local method which will internally invoke "get" API on the found resource
+ getResourceRepresentation(ocResource);
+ }
+ }
+
+ @Override
+ public synchronized void onFindResourceFailed(Throwable throwable, String uri) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ IotivityScanner.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ IotivityScanner.msgError("Uri: " + uri + " Error code: " + errCode);
+ }
+
+ IotivityScanner.msgError("Find resource failed");
+ }
+
+ /**
+ * Resource found listener specifically for links.
+ */
+ class ResourceFoundListener implements OcPlatform.OnResourceFoundListener {
+
+ private String mParentUri;
+ private String mHref; // expected link uri
+
+ ResourceFoundListener(String resourceUri, String href) {
+ mParentUri = resourceUri;
+ mHref = href;
+ }
+
+ public synchronized void onResourceFound(OcResource ocResource) {
+ if (null == ocResource) {
+ IotivityScanner.msgError("Found resource is invalid");
+ return;
+ }
+
+ String resourceUri = ocResource.getUri();
+
+ boolean tracked = false;
+
+ if (resourceUri.equalsIgnoreCase(mHref)) {
+ if (!mResourceLookup.containsKey(resourceUri)) {
+ IotivityScanner.msg("URI of the new linked resource: " + resourceUri);
+
+ if (resourceUri.startsWith(BinarySwitch.UPNP_OIC_URI_PREFIX_BINARY_SWITCH)
+ || resourceUri.startsWith(BinarySwitch.OCF_OIC_URI_PREFIX_BINARY_SWITCH)) {
+ BinarySwitch binarySwitch = new BinarySwitch();
+ binarySwitch.setUri(resourceUri);
+
+ // Update the device
+ Light light = (Light) mResourceLookup.get(mParentUri);
+ if (light != null) {
+ light.setBinarySwitch(binarySwitch);
+ mResourceLookup.put(resourceUri, binarySwitch);
+ tracked = true;
+ }
+
+ } else if (resourceUri.startsWith(Brightness.UPNP_OIC_URI_PREFIX_BRIGHTNESS)
+ || resourceUri.startsWith(Brightness.OCF_OIC_URI_PREFIX_BRIGHTNESS)) {
+ Brightness brightness = new Brightness();
+ brightness.setUri(resourceUri);
+
+ // Update the device
+ Light light = (Light) mResourceLookup.get(mParentUri);
+ if (light != null) {
+ light.setBrightness(brightness);
+ mResourceLookup.put(resourceUri, brightness);
+ tracked = true;
+ }
+
+ } else if (resourceUri.startsWith(Configuration.OCF_OIC_URI_PREFIX_CONFIG)) {
+ Configuration config = new Configuration();
+ config.setUri(resourceUri);
+
+ // Update the device
+ Light light = (Light) mResourceLookup.get(mParentUri);
+ if (light != null) {
+ light.setConfiguration(config);
+ mResourceLookup.put(resourceUri, config);
+ tracked = true;
+ }
+
+ } else {
+ // Unexpected resource
+ IotivityScanner.msg("URI of an unexpected resource: " + resourceUri);
+ }
+
+ mIotivityResourceLookup.put(resourceUri, ocResource);
+
+ if (tracked) {
+ // Call a local method which will internally invoke "get" API on the found resource
+ getResourceRepresentation(ocResource);
+
+ // Call a local method which will internally invoke "observe" API on the found resource
+ observeFoundResource(ocResource);
+ }
+ }
+ }
+ }
+
+ public synchronized void onFindResourceFailed(Throwable throwable, String uri) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ IotivityScanner.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ IotivityScanner.msgError("Uri: " + uri + " Error code: " + errCode);
+ }
+
+ IotivityScanner.msgError("Find resource failed");
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "findResources" request
+ * completes successfully
+ *
+ * @param ocResources
+ * array of found resources
+ */
+ @Override
+ public synchronized void onResourcesFound(OcResource[] ocResources) {
+ if (null == ocResources) {
+ IotivityScanner.msgError("Found resources is invalid");
+ return;
+ }
+
+ for (OcResource ocResource : ocResources) {
+ onResourceFound(ocResource);
+ }
+ }
+
+ @Override
+ public synchronized void onFindResourcesFailed(Throwable throwable, String uri) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ IotivityScanner.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ IotivityScanner.msgError("Uri: " + uri + " Error code: " + errCode);
+ }
+
+ IotivityScanner.msgError("Find resource failed");
+ }
+
+ /**
+ * Local method to get representation of a found resource
+ *
+ * @param ocResource found resource
+ */
+ private void getResourceRepresentation(OcResource ocResource) {
+
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "get" API with a OcResource.OnGetListener event listener implementation
+ ocResource.get(queryParams, this);
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Error occurred while invoking \"get\" API -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "get" request completes successfully
+ *
+ * @param list list of the header options
+ * @param ocRepresentation representation of a resource
+ */
+ @Override
+ public synchronized void onGetCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation) {
+
+ try {
+ // Read attribute values into local representation of resource
+ final String ocRepUri = ocRepresentation.getUri();
+ if (ocRepUri != null && !ocRepUri.isEmpty()) {
+ IotivityScanner.msg("Get Resource URI: " + ocRepUri);
+
+ Resource resource = mResourceLookup.get(ocRepUri);
+ if (resource != null) {
+ resource.setOcRepresentation(ocRepresentation);
+// IotivityScanner.msg("Get Resource attributes: " + resource.toString());
+
+ if (resource instanceof Device) {
+ Device device = (Device) resource;
+ Links links = device.getLinks();
+ for (Link link : links.getLinks()) {
+ String href = link.getHref();
+ // rt could be String or String[]
+ Object rt = link.getRt();
+ String rtAsString = null;
+ if (rt instanceof String) {
+ rtAsString = (String) rt;
+
+ } else if (rt instanceof String[]) {
+ if (((String[]) rt).length > 0) {
+ rtAsString = ((String[]) rt)[0];
+ } else {
+ IotivityScanner.msgError("(String[])rt is empty");
+ }
+
+ } else {
+ IotivityScanner.msgError("Unknown rt type of " + rt.getClass().getName());
+ }
+
+ if ((rtAsString != null) && (!mResourceLookup.containsKey(href))) {
+ IotivityScanner.msg("Finding all resources of type " + rtAsString);
+ String requestUri = OcPlatform.WELL_KNOWN_QUERY + "?rt=" + rtAsString;
+ OcPlatform.findResource("", requestUri, EnumSet.of(OcConnectivityType.CT_DEFAULT), new ResourceFoundListener(ocRepUri, href));
+ }
+ }
+
+ if (resource instanceof Light) {
+ Light light = (Light) resource;
+
+ if (((light.getBinarySwitch() != null) && (light.getBinarySwitch().isInitialized())
+ && (light.getBrightness() != null) && light.getBrightness().isInitialized())
+ || (!light.hasLinksProperty())) {
+
+ mStaleResourceUriLookup.put(light.getUri(), System.currentTimeMillis());
+ }
+
+ } else {
+ // TODO: handle additional devices
+ }
+ }
+
+ } else {
+ IotivityScanner.msgError("Get No resource for uri " + ocRepUri);
+ }
+
+ } else {
+ IotivityScanner.msgError("Get No Resource URI");
+ }
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Get Failed to read the attributes of resource -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "get" request fails
+ *
+ * @param throwable exception
+ */
+ @Override
+ public synchronized void onGetFailed(Throwable throwable) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ IotivityScanner.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ IotivityScanner.msgError("Error code: " + errCode);
+ }
+ IotivityScanner.msgError("Failed to get representation of a found light resource");
+ }
+
+ /**
+ * Set state for a light resource
+ */
+ public void updateLight(String uri, boolean newState, int newLightLevel) {
+ OcResource ocResource = mIotivityResourceLookup.get(uri);
+ if (ocResource != null) {
+ putLightRepresentation(ocResource, newState, newLightLevel);
+ }
+ }
+
+ /**
+ * Rename a light resource
+ */
+ public void updateLight(String uri, String newName) {
+ OcResource ocResource = mIotivityResourceLookup.get(uri);
+ if (ocResource != null) {
+ putLightRepresentation(ocResource, newName);
+ }
+ }
+
+ /**
+ * Local method to put a different name for this light resource
+ */
+ private void putLightRepresentation(OcResource ocResource, String newName) {
+ final String resourceUri = ocResource.getUri();
+
+ Light light = (Light) mResourceLookup.get(resourceUri);
+ if (light != null && resourceUri.startsWith(Light.OCF_OIC_URI_PREFIX_LIGHT)) {
+ if (light.hasLinksProperty()) {
+ final Configuration config = light.getConfiguration();
+ if ((config != null) && (config.isInitialized())) {
+ config.setName(newName);
+ OcRepresentation configRepresentation = null;
+ try {
+ configRepresentation = config.getOcRepresentation();
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Failed to get OcRepresentation from a configuration -- " + e.toString());
+ }
+
+ if (configRepresentation != null) {
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "put" API with a new representation
+ OcResource configResource = mIotivityResourceLookup.get(config.getUri());
+ if (configResource != null) {
+ configResource.put(configRepresentation, queryParams, this);
+
+ } else {
+ IotivityScanner.msgError("No configuration for light uri " + resourceUri);
+ }
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Error occurred while invoking \"put\" API -- " + e.toString());
+ }
+ }
+
+ } else {
+ if (config == null) {
+ IotivityScanner.msgError("No configuration for light uri " + resourceUri);
+
+ } else {
+ IotivityScanner.msgError("No configuration (initialized) for light uri " + resourceUri);
+ }
+ }
+
+ } else {
+ // properties are on the device
+ light.setName(newName);
+ }
+
+ } else if (!resourceUri.startsWith(Light.OCF_OIC_URI_PREFIX_LIGHT)) {
+// IotivityScanner.msg("No configuration available for light uri " + resourceUri);
+
+ } else {
+ IotivityScanner.msgError("No light for uri " + resourceUri);
+ }
+ }
+
+ /**
+ * Local method to put a different state for this light resource
+ */
+ private void putLightRepresentation(OcResource ocResource, boolean newState, int newLightLevel) {
+ final String resourceUri = ocResource.getUri();
+
+ Light light = (Light) mResourceLookup.get(resourceUri);
+ if (light != null) {
+ // set new values
+ if (light.hasLinksProperty()) {
+ // actually, set directly on the service (avoid possible conflict if auto discover is running)
+ // light.setState(newState);
+ // light.setLightLevel(newLightLevel);
+
+ final BinarySwitch binarySwitch = light.getBinarySwitch();
+ if ((binarySwitch != null) && (binarySwitch.isInitialized())) {
+ binarySwitch.setValue(newState);
+ OcRepresentation binarySwitchRepresentation = null;
+ try {
+ binarySwitchRepresentation = binarySwitch.getOcRepresentation();
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Failed to get OcRepresentation from a binary switch -- " + e.toString());
+ }
+
+ if (binarySwitchRepresentation != null) {
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "put" (or "post") API with a new representation
+ OcResource binarySwitchResource = mIotivityResourceLookup.get(binarySwitch.getUri());
+ if (binarySwitchResource != null) {
+ if (binarySwitchResource.getUri().startsWith(BinarySwitch.UPNP_OIC_URI_PREFIX_BINARY_SWITCH)) {
+ // upnp bridge requires 'post'
+ binarySwitchResource.post(binarySwitchRepresentation, queryParams, this);
+ } else {
+ binarySwitchResource.put(binarySwitchRepresentation, queryParams, this);
+ }
+
+ } else {
+ IotivityScanner.msgError("No binary switch for light uri " + resourceUri);
+ }
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Error occurred while invoking \"put\" API -- " + e.toString());
+ }
+ }
+
+ } else {
+ if (binarySwitch == null) {
+ IotivityScanner.msgError("No binary switch for light uri " + resourceUri);
+
+ } else {
+ IotivityScanner.msgError("No binary switch (initialized) for light uri " + resourceUri);
+ }
+ }
+
+ Brightness brightness = light.getBrightness();
+ if ((brightness != null) && (brightness.isInitialized())) {
+ brightness.setBrightness(newLightLevel);
+ OcRepresentation brightnessRepresentation = null;
+ try {
+ brightnessRepresentation = brightness.getOcRepresentation();
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Failed to get OcRepresentation from a brightness -- " + e.toString());
+ }
+
+ if (brightnessRepresentation != null) {
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "put" (or "post") API with a new representation
+ OcResource brightnessResource = mIotivityResourceLookup.get(brightness.getUri());
+ if (brightnessResource != null) {
+ if (brightnessResource.getUri().startsWith(Brightness.UPNP_OIC_URI_PREFIX_BRIGHTNESS)) {
+ // upnp bridge requires 'post'
+ brightnessResource.post(brightnessRepresentation, queryParams, this);
+ } else {
+ brightnessResource.put(brightnessRepresentation, queryParams, this);
+ }
+
+ } else {
+ IotivityScanner.msgError("No brightness for light uri " + resourceUri);
+ }
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Error occurred while invoking \"put\" API -- " + e.toString());
+ }
+ }
+
+ } else {
+ if (brightness == null) {
+ IotivityScanner.msgError("No brightness for light uri " + resourceUri);
+
+ } else {
+ IotivityScanner.msgError("No brightness (initialized) for light uri " + resourceUri);
+ }
+ }
+
+ } else {
+ // properties are on the device
+ light.setState(newState);
+ light.setLightLevel(newLightLevel);
+
+ OcRepresentation lightRepresentation = null;
+ try {
+ lightRepresentation = light.getOcRepresentation();
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Failed to get OcRepresentation from light -- " + e.toString());
+ }
+
+ if (lightRepresentation != null) {
+ Map<String, String> queryParams = new HashMap<>();
+ try {
+ // Invoke resource's "put" API with a new representation
+ ocResource.put(lightRepresentation, queryParams, this);
+
+ } catch (OcException e) {
+ AlexaIotivityBridgeDemo.msgError("Error occurred while invoking \"put\" API -- " + e.toString());
+ }
+ }
+ }
+
+ } else {
+ IotivityScanner.msgError("No light for uri " + resourceUri);
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "put" request completes successfully
+ *
+ * @param list list of the header options
+ * @param ocRepresentation representation of a resource
+ */
+ @Override
+ public synchronized void onPutCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation) {
+
+ try {
+ // Read attribute values into local representation of resource
+ final String ocRepUri = ocRepresentation.getUri();
+ if (ocRepUri != null && !ocRepUri.isEmpty()) {
+// IotivityScanner.msg("Put Resource URI: " + ocRepUri);
+
+ Resource resource = mResourceLookup.get(ocRepUri);
+ if (resource != null) {
+ resource.setOcRepresentation(ocRepresentation);
+ IotivityScanner.msg("Put Resource attributes: " + resource.toString());
+
+ } else {
+ IotivityScanner.msgError("Put No resource for uri " + ocRepUri);
+ }
+
+ } else {
+ IotivityScanner.msgError("Put No Resource URI");
+ }
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Put Failed to create resource representation -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "put" request fails
+ *
+ * @param throwable exception
+ */
+ @Override
+ public synchronized void onPutFailed(Throwable throwable) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ IotivityScanner.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ IotivityScanner.msgError("Error code: " + errCode);
+ }
+ IotivityScanner.msgError("Failed to \"put\" a new representation");
+ }
+
+ /**
+ * An event handler to be executed whenever a "post" request completes successfully
+ *
+ * @param list list of the header options
+ * @param ocRepresentation representation of a resource
+ */
+ @Override
+ public synchronized void onPostCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation) {
+
+ try {
+ // Read attribute values into local representation of resource
+ final String ocRepUri = ocRepresentation.getUri();
+ if (ocRepUri != null && !ocRepUri.isEmpty()) {
+// IotivityScanner.msg("Post Resource URI: " + ocRepUri);
+
+ Resource resource = mResourceLookup.get(ocRepUri);
+ if (resource != null) {
+ resource.setOcRepresentation(ocRepresentation);
+ IotivityScanner.msg("Post Resource attributes: " + resource.toString());
+
+ } else {
+ IotivityScanner.msgError("Post No resource for uri " + ocRepUri);
+ }
+
+ } else {
+ IotivityScanner.msgError("Post No Resource URI");
+ }
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Post Failed to create resource representation -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "post" request fails
+ *
+ * @param throwable exception
+ */
+ @Override
+ public synchronized void onPostFailed(Throwable throwable) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ IotivityScanner.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ IotivityScanner.msgError("Error code: " + errCode);
+ }
+ IotivityScanner.msgError("Failed to \"post\" a new representation");
+ }
+
+ /**
+ * Local method to start observing this resource
+ *
+ * @param ocResource found resource
+ */
+ private void observeFoundResource(OcResource ocResource) {
+ try {
+ // Invoke resource's "observe" API with a observe type
+ ocResource.observe(ObserveType.OBSERVE, new HashMap<String, String>(), this);
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Error occurred while invoking \"observe\" API -- " + e.toString());
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "observe" request completes successfully
+ *
+ * @param list list of the header options
+ * @param ocRepresentation representation of a resource
+ * @param sequenceNumber sequence number
+ */
+ @Override
+ public synchronized void onObserveCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation, int sequenceNumber) {
+ if (OcResource.OnObserveListener.REGISTER == sequenceNumber) {
+ IotivityScanner.msg("Observe registration action is successful");
+ } else {
+ IotivityScanner.msg("Observe sequence number " + sequenceNumber);
+ }
+
+ if ((sequenceNumber > 0) && (sequenceNumber < (OcResource.OnObserveListener.MAX_SEQUENCE_NUMBER + 1))) {
+ onGetCompleted(list, ocRepresentation);
+ }
+ }
+
+ /**
+ * An event handler to be executed whenever a "observe" request fails
+ *
+ * @param throwable exception
+ */
+ @Override
+ public synchronized void onObserveFailed(Throwable throwable) {
+ if (throwable instanceof OcException) {
+ OcException ocEx = (OcException) throwable;
+ IotivityScanner.msgError(ocEx.toString());
+ ErrorCode errCode = ocEx.getErrorCode();
+ // do something based on errorCode
+ IotivityScanner.msgError("Error code: " + errCode);
+ }
+ IotivityScanner.msgError("Observation of the found light resource has failed");
+ }
+
+ public synchronized void cancelObserve() {
+ for (OcResource ocResource : mIotivityResourceLookup.values()) {
+ if (ocResource.getUri().contains(Light.OIC_URI_PREFIX_LIGHT)) {
+ try {
+ ocResource.cancelObserve();
+ } catch (OcException e) {
+ IotivityScanner.msgError("Error occurred while invoking \"cancelObserve\" API for resource "
+ + ocResource.getUri() + " -- " + e.toString());
+ }
+ }
+ }
+ }
+
+ class DeviceFoundListener implements OcPlatform.OnDeviceFoundListener {
+
+ Light light;
+
+ public DeviceFoundListener(Light light) {
+ this.light = light;
+ }
+
+ @Override
+ public void onDeviceFound(OcRepresentation ocRepresentation) {
+ try {
+ if (ocRepresentation.hasAttribute("n")) {
+ String name = ocRepresentation.getValue("n");
+ light.setName(name);
+// IotivityScanner.msg("OCF device found callback: 'n' = " + name);
+ } else {
+ IotivityScanner.msgError("'n' attribute not found for device " + light.toString());
+ }
+
+ } catch (OcException e) {
+ IotivityScanner.msgError("Get 'n' attribute failed for device " + light.toString());
+ e.printStackTrace();
+ }
+ }
+ };
+
+ public class StaleResourcePurgeTask extends TimerTask {
+ private int frequency;
+
+ public StaleResourcePurgeTask(int frequency) {
+ this.frequency = frequency;
+ }
+
+ @Override
+ public void run() {
+ try {
+ long now = System.currentTimeMillis();
+ for (Map.Entry<String, Long> entry : mStaleResourceUriLookup.entrySet()) {
+ if (entry.getValue() < (now - 3 * frequency * 1000)) {
+ // uri not seen in 3 tries, remove from maps
+ String key = entry.getKey();
+ IotivityScanner.msg("Removing stale uri " + key);
+ Light light = (Light) mResourceLookup.get(key);
+ for (Link link : light.getLinks().getLinks()) {
+ IotivityScanner.msg("Removing stale uri link " + link.getHref());
+ mIotivityResourceLookup.remove(link.getHref());
+ mResourceLookup.remove(link.getHref());
+ }
+ mIotivityResourceLookup.remove(key);
+ mResourceLookup.remove(key);
+ mStaleResourceUriLookup.remove(key);
+ }
+ }
+
+ } catch (Exception e) {
+ IotivityScanner.msgError("Error running StaleResourcePurgeTask: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Light.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Light.java
new file mode 100644
index 0000000..694ba12
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Light.java
@@ -0,0 +1,177 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2017 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Light
+ *
+ * This class is used by IotivityClient to create an object representation of a remote light device
+ * and update the values depending on the server response
+ */
+public class Light extends Device {
+
+ public static final String OIC_TYPE_DEVICE_LIGHT = "oic.d.light";
+ public static final String OCF_OIC_URI_PREFIX_LIGHT = "/ocf/light/";
+ public static final String UPNP_OIC_URI_PREFIX_LIGHT = "/upnp/light/";
+ public static final String OIC_URI_PREFIX_LIGHT = "/light/";
+
+
+ private BinarySwitch mBinarySwitch;
+ private Brightness mBrightness;
+ private Configuration mConfig;
+
+ private String mName = "Unknown";
+ private boolean mState = BinarySwitch.DEFAULT_VALUE;
+ private int mLightLevel = Brightness.DEFAULT_BRIGHTNESS;
+
+ public Light() {
+ super();
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) throws OcException {
+ super.setOcRepresentation(rep);
+ if (rep.hasAttribute(Configuration.NAME_KEY)) {
+ Object obj = rep.getValue(Configuration.NAME_KEY);
+ if (obj instanceof String) {
+ mName = (String) obj;
+ }
+ }
+ if (rep.hasAttribute(BinarySwitch.VALUE_KEY)) {
+ Object obj = rep.getValue(BinarySwitch.VALUE_KEY);
+ if (obj instanceof Boolean) {
+ mState = (Boolean) obj;
+ }
+ }
+ if (rep.hasAttribute(Brightness.BRIGHTNESS_KEY)) {
+ Object obj = rep.getValue(Brightness.BRIGHTNESS_KEY);
+ if (obj instanceof Integer) {
+ mLightLevel = (Integer) obj;
+ }
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() throws OcException {
+ OcRepresentation rep = super.getOcRepresentation();
+ rep.setValue(Configuration.NAME_KEY, mName);
+ rep.setValue(BinarySwitch.VALUE_KEY, mState);
+ rep.setValue(Brightness.BRIGHTNESS_KEY, mLightLevel);
+ return rep;
+ }
+
+ public BinarySwitch getBinarySwitch() {
+ return mBinarySwitch;
+ }
+
+ public void setBinarySwitch(BinarySwitch binarySwitch) {
+ mBinarySwitch = binarySwitch;
+ }
+
+ public Brightness getBrightness() {
+ return mBrightness;
+ }
+
+ public void setBrightness(Brightness brightness) {
+ mBrightness = brightness;
+ }
+
+ public Configuration getConfiguration() {
+ return mConfig;
+ }
+
+ public void setConfiguration(Configuration config) {
+ mConfig = config;
+ }
+
+ public String getName() {
+ if (mConfig != null) {
+ mName = mConfig.getName();
+ }
+
+ return mName;
+ }
+
+ public void setName(String name) {
+ if (mConfig != null) {
+ mConfig.setName(name);
+
+ } else {
+ mName = name;
+ }
+ }
+
+ public boolean getState() {
+ if (mBinarySwitch != null) {
+ mState = mBinarySwitch.getValue();
+ }
+
+ return mState;
+ }
+
+ public void setState(boolean state) {
+ if (mBinarySwitch != null) {
+ mBinarySwitch.setValue(state);
+
+ } else {
+ mState = state;
+ }
+ }
+
+ public int getLightLevel() {
+ if (mBrightness != null) {
+ mLightLevel = mBrightness.getBrightness();
+ }
+
+ return mLightLevel;
+ }
+
+ public void setLightLevel(int lightLevel) {
+ if (mBrightness != null) {
+ mBrightness.setBrightness(lightLevel);
+
+ } else {
+ mLightLevel = lightLevel;
+ }
+ }
+
+ @Override
+ public String toString() {
+ String binarySwitchAsString = mBinarySwitch != null ? mBinarySwitch.toString() : "binary switch is null";
+ String brightnessAsString = mBrightness != null ? mBrightness.toString() : "brightness is null";
+ String configAsString = mConfig != null ? mConfig.toString() : "configuration is null";
+
+ if (mConfig != null) {
+ return "[" + super.toString() +
+ ", " + binarySwitchAsString +
+ ", " + brightnessAsString +
+ ", " + configAsString + "]";
+ } else {
+ return "[" + super.toString() +
+ ", " + Configuration.NAME_KEY + ": " + mName +
+ ", " + BinarySwitch.VALUE_KEY + ": " + mState +
+ ", " + Brightness.BRIGHTNESS_KEY + ": " + mLightLevel + "]";
+ }
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Link.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Link.java
new file mode 100644
index 0000000..530b285
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Link.java
@@ -0,0 +1,132 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2017 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Link
+ *
+ * This class is used by IotivityClient to create an object representation of a
+ * link of a remote device and update the values depending on the server
+ * response
+ */
+public class Link {
+
+ public static final String HREF_KEY = "href";
+ public static final String REL_KEY = "rel";
+ public static final String RT_KEY = "rt";
+
+ private String mHref;
+ private String mRel;
+ private Object mRt; // could be String or String[]
+
+ public Link() {
+ mHref = "";
+ mRel = "";
+ mRt = new Object();
+ }
+
+ public void setOcRepresentation(OcRepresentation ocRep) throws OcException {
+ if (ocRep.hasAttribute(HREF_KEY)) {
+ mHref = ocRep.getValue(HREF_KEY);
+ }
+ if (ocRep.hasAttribute(REL_KEY)) {
+ mRel = ocRep.getValue(REL_KEY);
+ }
+ if (ocRep.hasAttribute(RT_KEY)) {
+ mRt = ocRep.getValue(RT_KEY);
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() throws OcException {
+ OcRepresentation ocRep = new OcRepresentation();
+ ocRep.setValue(HREF_KEY, mHref);
+ ocRep.setValue(REL_KEY, mRel);
+ if (mRt instanceof String) {
+ ocRep.setValue(RT_KEY, (String) mRt);
+ } else if (mRt instanceof String[]) {
+ ocRep.setValue(RT_KEY, (String[]) mRt);
+ } else {
+ // this is gonna fail...
+ }
+
+ return ocRep;
+ }
+
+ public String getHref() {
+ return mHref;
+ }
+
+ public void setHref(String href) {
+ mHref = href;
+ }
+
+ public String getRel() {
+ return mRel;
+ }
+
+ public void setRel(String rel) {
+ mRel = rel;
+ }
+
+ public Object getRt() {
+ return mRt;
+ }
+
+ public void setRt(Object rt) {
+ mRt = rt;
+ }
+
+ @Override
+ public String toString() {
+ String rtAsString = null;
+ Object rt = getRt();
+ if (rt instanceof String) {
+ rtAsString = (String) rt;
+
+ } else if (rt instanceof String[]) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ boolean first = true;
+ for (String type : (String[]) rt) {
+ if (!first) {
+ sb.append(", ");
+ }
+ if (type != null) {
+ sb.append(type.toString());
+ }
+ first = false;
+ }
+ sb.append("]");
+ rtAsString = sb.toString();
+
+ } else {
+ rtAsString = "Unknown rt type of " + rt.getClass().getName();
+ }
+
+ return "[" + HREF_KEY + ": " + getHref() + ", " + REL_KEY + ": " + getRel() + ", " + RT_KEY + ": " + rtAsString
+ + "]";
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Links.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Links.java
new file mode 100644
index 0000000..945f9d5
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Links.java
@@ -0,0 +1,93 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2016 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Links
+ *
+ * This class is used by IotivityClient to create an object representation of the links of a remote device
+ * and update the values depending on the server response
+ */
+public class Links {
+
+ public static final String LINKS_KEY = "links";
+
+ private Link[] mLinks;
+
+ public Links() {
+ mLinks = new Link[0];
+ }
+
+ public void setOcRepresentation(OcRepresentation[] ocRepLinks) throws OcException {
+ if ((ocRepLinks != null) && (ocRepLinks.length > 0)) {
+ mLinks = new Link[ocRepLinks.length];
+ int index = 0;
+ for (OcRepresentation ocRepLink : ocRepLinks) {
+ mLinks[index] = new Link();
+ mLinks[index].setOcRepresentation(ocRepLink);
+ ++index;
+ }
+ }
+ }
+
+ public OcRepresentation[] getOcRepresentation() throws OcException {
+ OcRepresentation[] ocRepLinks = new OcRepresentation[mLinks.length];
+ int index = 0;
+ for (Link link : mLinks) {
+ OcRepresentation ocRepLink = link.getOcRepresentation();
+ ocRepLinks[index] = ocRepLink;
+ ++index;
+ }
+ return ocRepLinks;
+ }
+
+ public Link[] getLinks() {
+ return mLinks;
+ }
+
+ public void setLinks(Link[] links) {
+ mLinks = (links != null) ? links : new Link[0];
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ boolean first = true;
+ for (Link link : mLinks) {
+ if (!first) {
+ sb.append(", ");
+ }
+ if (link != null) {
+ sb.append(link.toString());
+ }
+ first = false;
+ }
+ sb.append("]");
+
+ return sb.toString();
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java
new file mode 100644
index 0000000..7520e6f
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java
@@ -0,0 +1,115 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * This class encapsulates the names property files. The names property file is
+ * used for renaming devices which cannot be renamed for upnp clients.
+ */
+public class NamesPropertyFile {
+
+ static private Properties namesProperties;
+ static private File namesPropertyFile;
+
+ static private NamesPropertyFile instance;
+
+ static {
+ try {
+ namesProperties = new Properties();
+ namesPropertyFile = new File("names.prop");
+ instance = new NamesPropertyFile();
+
+ } catch (Exception e) {
+ AlexaIotivityBridgeDemo.msgError("Error creating names property file instance.");
+ }
+ }
+
+ private NamesPropertyFile() {
+ // read the names property file
+ FileInputStream inStream = null;
+ try {
+ if (namesPropertyFile.exists() && namesPropertyFile.length() > 0) {
+ inStream = new FileInputStream(namesPropertyFile);
+ namesProperties.loadFromXML(inStream);
+ namesProperties.list(System.out);
+ }
+
+ } catch (IOException e) {
+ AlexaIotivityBridgeDemo.msgError("Error loading name properties: " + e.toString());
+ e.printStackTrace();
+
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ AlexaIotivityBridgeDemo.msgError("Error closing name properties file: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static NamesPropertyFile getInstance() {
+ return instance;
+ }
+
+ public boolean hasUri(String uri) {
+ return namesProperties.containsKey(uri);
+ }
+
+ public String getNameForUri(String uri) {
+ return (String) namesProperties.get(uri);
+ }
+
+ public void updateNamesProperty(String uri, String name) {
+ // update names property file
+ namesProperties.put(uri, name);
+ FileOutputStream outStream = null;
+ try {
+ outStream = new FileOutputStream(namesPropertyFile);
+ namesProperties.storeToXML(outStream, null);
+
+ } catch (IOException e) {
+ AlexaIotivityBridgeDemo.msgError("Error storing name properties: " + e.toString());
+ e.printStackTrace();
+ }
+
+ finally {
+ if (outStream != null) {
+ try {
+ outStream.close();
+ } catch (IOException e) {
+ AlexaIotivityBridgeDemo.msgError("Error closing name properties file: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Resource.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Resource.java
new file mode 100644
index 0000000..843af23
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Resource.java
@@ -0,0 +1,101 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2016 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Resource
+ *
+ * This class is used by IotivityClient to create an object representation of a remote resource
+ * and update the values depending on the server response
+ */
+abstract public class Resource {
+
+ public static final String NAME_KEY = "name";
+ public static final String URI_KEY = "uri";
+
+ private String mName;
+ private String mUri;
+
+ public Resource() {
+ mName = "";
+ mUri = "";
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) throws OcException {
+ if (rep.hasAttribute(URI_KEY)) {
+ setUri((String) rep.getValue(URI_KEY));
+ }
+ if (rep.hasAttribute(NAME_KEY)) {
+ String nameToUse = null;
+ // Fake for UPnP Bridge... use name from property file
+ if (NamesPropertyFile.getInstance().hasUri(mUri)) {
+ nameToUse = NamesPropertyFile.getInstance().getNameForUri(mUri);
+ }
+
+ if (nameToUse != null) {
+ setName(nameToUse);
+
+ } else {
+ setName((String) rep.getValue(NAME_KEY));
+ }
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() throws OcException {
+ OcRepresentation rep = new OcRepresentation();
+ if ((mUri != null) && (!mUri.isEmpty())) {
+ rep.setValue(URI_KEY, mUri);
+ rep.setUri(mUri);
+ }
+ if ((mName != null) && (!mName.isEmpty())) {
+ rep.setValue(NAME_KEY, mName);
+ }
+
+ return rep;
+ }
+
+ public String getUri() {
+ return mUri;
+ }
+
+ public void setUri(String uri) {
+ mUri = (uri != null) ? uri : "";
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public void setName(String name) {
+ mName = (name != null) ? name : "";
+ }
+
+ @Override
+ public String toString() {
+ return "[" + URI_KEY + ": " + getUri() +
+ ", " + NAME_KEY + ": " + getName() + "]";
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Service.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Service.java
new file mode 100644
index 0000000..7ed4b08
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/Service.java
@@ -0,0 +1,52 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2016 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Service
+ *
+ * This class is used by IotivityClient to create an object representation of a remote service
+ * and update the values depending on the server response
+ */
+abstract public class Service extends Resource {
+
+ public Service() {
+ super();
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) throws OcException {
+ super.setOcRepresentation(rep);
+ }
+
+ public OcRepresentation getOcRepresentation() throws OcException {
+ return super.getOcRepresentation();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/UpdateAcceptedTopicListener.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/UpdateAcceptedTopicListener.java
new file mode 100644
index 0000000..636a6cf
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/UpdateAcceptedTopicListener.java
@@ -0,0 +1,39 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import com.amazonaws.services.iot.client.AWSIotMessage;
+import com.amazonaws.services.iot.client.AWSIotQos;
+import com.amazonaws.services.iot.client.AWSIotTopic;
+
+public class UpdateAcceptedTopicListener extends AWSIotTopic {
+
+ public UpdateAcceptedTopicListener(String topic, AWSIotQos qos) {
+ super(topic, qos);
+ }
+
+ @Override
+ public void onMessage(AWSIotMessage message) {
+// AlexaIotivityBridgeDemo.msg("<<< " + message.getStringPayload());
+ }
+}
diff --git a/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/UpdatePublisherListener.java b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/UpdatePublisherListener.java
new file mode 100644
index 0000000..ed12427
--- /dev/null
+++ b/alexa-iotivity-bridge-demo/src/main/java/org/iotivity/base/examples/UpdatePublisherListener.java
@@ -0,0 +1,48 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import com.amazonaws.services.iot.client.AWSIotMessage;
+import com.amazonaws.services.iot.client.AWSIotQos;
+
+public class UpdatePublisherListener extends AWSIotMessage {
+
+ public UpdatePublisherListener(String topic, AWSIotQos qos, String payload) {
+ super(topic, qos, payload);
+ }
+
+ @Override
+ public void onSuccess() {
+ AlexaIotivityBridgeDemo.msg(">>> " + getStringPayload());
+ }
+
+ @Override
+ public void onFailure() {
+ AlexaIotivityBridgeDemo.msg("update failed for " + getStringPayload());
+ }
+
+ @Override
+ public void onTimeout() {
+ AlexaIotivityBridgeDemo.msg("update timeout for " + getStringPayload());
+ }
+}
diff --git a/alexa-smart-home-skill-lambda/LICENSE.md b/alexa-smart-home-skill-lambda/LICENSE.md
new file mode 100644
index 0000000..b786745
--- /dev/null
+++ b/alexa-smart-home-skill-lambda/LICENSE.md
@@ -0,0 +1,195 @@
+Copyright (c) 2017 IoTivity
+<http://www.iotivity.org/>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+<http://www.apache.org/licenses/LICENSE-2.0>
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+```
+-------------------------------------------------------------------------
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+```
diff --git a/alexa-smart-home-skill-lambda/README.md b/alexa-smart-home-skill-lambda/README.md
new file mode 100644
index 0000000..2273ee0
--- /dev/null
+++ b/alexa-smart-home-skill-lambda/README.md
@@ -0,0 +1,28 @@
+<!---
+ ~ //******************************************************************
+ ~ //
+ ~ // Copyright 2107 Intel Corporation All Rights Reserved.
+ ~ //
+ ~ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ ~ //
+ ~ // Licensed under the Apache License, Version 2.0 (the "License");
+ ~ // you may not use this file except in compliance with the License.
+ ~ // You may obtain a copy of the License at
+ ~ //
+ ~ // http://www.apache.org/licenses/LICENSE-2.0
+ ~ //
+ ~ // Unless required by applicable law or agreed to in writing, software
+ ~ // distributed under the License is distributed on an "AS IS" BASIS,
+ ~ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ // See the License for the specific language governing permissions and
+ ~ // limitations under the License.
+ ~ //
+ ~ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ --->
+
+## Install required node.js modules
+
+You will need to run npm install to create a node_modules folder.
+
+ $ npm install aws-sdk
+
diff --git a/alexa-smart-home-skill-lambda/index.js b/alexa-smart-home-skill-lambda/index.js
new file mode 100644
index 0000000..ced7734
--- /dev/null
+++ b/alexa-smart-home-skill-lambda/index.js
@@ -0,0 +1,547 @@
+"use strict";
+
+const AWS = require("aws-sdk");
+const uuidV4 = require("uuid/v4");
+
+// replace with endpoint from AWS IoT Device
+const iotData = new AWS.IotData({endpoint:"a2a16j9xf0mmy6.iot.us-east-1.amazonaws.com", region:"us-east-1"});
+// replace with Thing Name for AWS IoT Device
+const thingName = "LeetoniaLinuxSystem";
+// replace with skill's Application Id
+const APP_ID = "amzn1.ask.skill.26df3d97-ba4d-44c4-aee5-0f20cce5375b";
+const SKILL_NAME = "AlexaIotivityHomeSkill";
+
+function generateMessageId() {
+ return uuidV4();
+}
+
+function generateDevice(endpointId, friendlyName, uri) {
+ return {
+ endpointId: endpointId,
+ manufacturerName: "Intel",
+ friendlyName: friendlyName,
+ description: uri,
+ displayCategories: [ "LIGHT" ],
+ cookie: {},
+ capabilities: [
+ {
+ type: "AlexaInterface",
+ interface: "Alexa",
+ version: "3"
+ },
+ {
+ type: "AlexaInterface",
+ interface: "Alexa.EndpointHealth",
+ version: "3",
+ properties: {
+ supported: [
+ {
+ name: "connectivity"
+ }
+ ],
+ proactivelyReported: true,
+ retrievable: true
+ }
+ },
+ {
+ type: "AlexaInterface",
+ interface: "Alexa.PowerController",
+ version: "3",
+ properties: {
+ supported: [
+ {
+ name: "powerState"
+ }
+ ],
+ proactivelyReported: true,
+ retrievable: true
+ }
+ },
+ {
+ type: "AlexaInterface",
+ interface: "Alexa.BrightnessController",
+ version: "3",
+ properties: {
+ supported: [
+ {
+ name: "brightness"
+ }
+ ],
+ proactivelyReported: true,
+ retrievable: true
+ }
+ }
+ ]
+ };
+}
+
+function generateStateResponse(endpointId, correlationToken, powerOn, brightness) {
+ const currentTime = new Date().toISOString();
+ return {
+ context: {
+ properties: [
+ {
+ namespace: "Alexa.EndpointHealth",
+ name: "connectivity",
+ value: {
+ value: "OK"
+ },
+ timeOfSample: currentTime,
+ uncertaintyInMilliseconds: 1000
+ },
+ {
+ namespace: "Alexa.PowerController",
+ name: "powerState",
+ value: powerOn ? "ON" : "OFF",
+ timeOfSample: currentTime,
+ uncertaintyInMilliseconds: 1000
+ },
+ {
+ namespace: "Alexa.BrightnessController",
+ name: "brightness",
+ value: brightness,
+ timeOfSample: currentTime,
+ uncertaintyInMilliseconds: 1000
+ }
+ ]
+ },
+ event: {
+ header: {
+ namespace: "Alexa",
+ name: "StateReport",
+ payloadVersion: "3",
+ messageId: generateMessageId(),
+ correlationToken: correlationToken
+ },
+ endpoint: {
+ scope: {
+ type: "BearerToken",
+ token: "access-token-from-Amazon"
+ },
+ endpointId: endpointId
+ },
+ payload: {}
+ }
+ };
+}
+
+function generateResponse(namespace, name, value, endpointId, correlationToken) {
+ return {
+ context: {
+ properties: [
+ {
+ namespace: namespace,
+ name: name,
+ value: value,
+ timeOfSample: new Date().toISOString(),
+ uncertaintyInMilliseconds: 1000
+ }
+ ]
+ },
+ event: {
+ header: {
+ namespace: "Alexa",
+ name: "Response",
+ payloadVersion: "3",
+ messageId: generateMessageId(),
+ correlationToken: correlationToken
+ },
+ endpoint: {
+ scope: {
+ type: "BearerToken",
+ token: "access-token-from-Amazon"
+ },
+ endpointId: endpointId
+ },
+ payload: {}
+ }
+ };
+}
+
+function generateErrorResponse(type, message, endpointId, correlationToken) {
+ return {
+ event: {
+ header: {
+ namespace: "Alexa",
+ name: "ErrorResponse",
+ payloadVersion: "3",
+ messageId: generateMessageId(),
+ correlationToken: correlationToken
+ },
+ endpoint: {
+ scope: {
+ type: "BearerToken",
+ token: "access-token-from-Amazon"
+ },
+ endpointId: endpointId
+ },
+ payload: {
+ type: type,
+ message: message
+ }
+ }
+ };
+}
+
+function isValidToken(userAccessToken) {
+ // TODO:
+ return true;
+}
+
+function isDeviceOnline(endpointId, userAccessToken) {
+ // TODO:
+ console.log("DEBUG", "isDeviceOnline -- endpointId: " + endpointId);
+ return true;
+}
+
+function getDevicesFromAwsIot(userAccessToken, callback) {
+ var devices = [];
+ const thingNameParam = {
+ thingName: thingName
+ };
+
+ iotData.getThingShadow(thingNameParam, function(err, data) {
+ console.log("DEBUG", "get thing shadow");
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (!err) {
+ const jsonPayload = JSON.parse(data.payload);
+ const lightDevices = jsonPayload.state.reported.lightDevices;
+ if (lightDevices.length > 0) {
+ jsonPayload.state.reported.lightDevices.forEach((item, index, array) => {
+ console.log("DEBUG", "lightDevices["+index+"]: "+JSON.stringify(item, null, 2));
+ const uriParts = item.uri.split("/");
+ const endpointId = uriParts[uriParts.length-1];
+ devices.push(generateDevice(endpointId, item.name, item.uri));
+ });
+ }
+ }
+
+ const response = {
+ event: {
+ header: {
+ namespace: "Alexa.Discovery",
+ name: "Discover.Response",
+ payloadVersion: "3",
+ messageId: generateMessageId()
+ },
+ payload: {
+ endpoints: devices
+ }
+ }
+ };
+
+ console.log("DEBUG", "Discovery Response: " + JSON.stringify(response, null, 2));
+ callback(null, response);
+ });
+}
+
+function getDeviceStateFromAwsIot(userAccessToken, endpointId, correlationToken, callback) {
+ var deviceFound = false;
+ const thingNameParam = {
+ thingName: thingName
+ };
+
+ iotData.getThingShadow(thingNameParam, function(err, data) {
+ console.log("DEBUG", "get thing shadow");
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (!err) {
+ const jsonPayload = JSON.parse(data.payload);
+ const lightDevices = jsonPayload.state.reported.lightDevices;
+ if (lightDevices.length > 0) {
+ deviceFound = jsonPayload.state.reported.lightDevices.some((item, index, array) => {
+ console.log("DEBUG", "lightDevices["+index+"]: "+JSON.stringify(item, null, 2));
+ const uriParts = item.uri.split("/");
+ const endpointIdFromUri = uriParts[uriParts.length-1];
+ if (endpointId == endpointIdFromUri) {
+ const response = generateStateResponse(endpointId, correlationToken, item.powerOn, item.brightness);
+ console.log("DEBUG", "StateReport Response: " + JSON.stringify(response, null, 2));
+
+ callback(null, response);
+ return true;
+ }
+ });
+ }
+ }
+ if (!deviceFound) {
+ const message = "EndpointId not found in device list";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("ENDPOINT_UNREACHABLE", message, endpointId, correlationToken));
+ }
+ });
+}
+
+function setAwsIotDeviceState(userAccessToken, endpointId, correlationToken, powerState, brightness, delta, callback) {
+ var deviceFound = false;
+ const thingNameParam = {
+ thingName: thingName
+ };
+
+ iotData.getThingShadow(thingNameParam, function(err, data) {
+ console.log("DEBUG", "get thing shadow");
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (!err) {
+ const jsonPayload = JSON.parse(data.payload);
+ const lightDevices = jsonPayload.state.reported.lightDevices;
+ var response;
+ if (lightDevices.length > 0) {
+ jsonPayload.state.reported.lightDevices.forEach((item, index, array) => {
+ console.log("DEBUG", "lightDevices["+index+"]: "+JSON.stringify(item, null, 2));
+ const uriParts = item.uri.split("/");
+ const endpointIdFromUri = uriParts[uriParts.length-1];
+ if (endpointId == endpointIdFromUri) {
+ deviceFound = true;
+ // Set the desired state of the found light
+ if (powerState) {
+ const powerOn = (powerState == "ON") ? true : false;
+ lightDevices[index].powerOn = powerOn;
+ response = generateResponse("Alexa.PowerController", "powerState", powerState, endpointId, correlationToken);
+ }
+ else if (brightness) {
+ brightness = Math.min(brightness, 100);
+ brightness = Math.max(brightness, 0);
+ lightDevices[index].brightness = brightness;
+ response = generateResponse("Alexa.BrightnessController", "brightness", brightness, endpointId, correlationToken);
+ }
+ else if (delta) {
+ lightDevices[index].brightness += delta;
+ lightDevices[index].brightness = Math.min(lightDevices[index].brightness, 100);
+ lightDevices[index].brightness = Math.max(lightDevices[index].brightness, 0);
+ response = generateResponse("Alexa.BrightnessController", "brightness", lightDevices[index].brightness, endpointId, correlationToken);
+ } else {
+ console.log("DEBUG", "no state change requested? for endpointId " + endpointId);
+ }
+ console.log("DEBUG", "desired lightDevices["+index+"]: "+JSON.stringify(lightDevices[index], null, 2));
+ }
+ });
+ }
+
+ if (deviceFound) {
+ const desiredLightState = {"state":{"desired":{"lightDevices":lightDevices}}};
+ const thingNameAndPayload = {
+ thingName: thingName,
+ payload: JSON.stringify(desiredLightState)
+ };
+ console.log("DEBUG", "payload: " + JSON.stringify(desiredLightState, null, 2));
+
+ iotData.updateThingShadow(thingNameAndPayload, function(err, data) {
+ console.log("DEBUG", "update thing shadow");
+ if (err) console.log(err, err.stack); // an error occurred
+ else console.log(data); // successful response
+
+ if (!err) {
+ console.log("DEBUG", "Response: " + JSON.stringify(response, null, 2));
+ callback(null, response);
+
+ } else {
+ const message = "Unable to set device state";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("INTERNAL_ERROR", message, endpointId, correlationToken));
+ }
+ });
+
+ } else {
+ const message = "EndpointId not found in device list";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("ENDPOINT_UNREACHABLE", message, endpointId, correlationToken));
+ }
+ }
+ });
+}
+
+function handleDiscovery(request, callback) {
+ console.log("DEBUG", "Discovery Request: " + JSON.stringify(request, null, 2));
+
+ /**
+ * Get the OAuth token from the request.
+ */
+ const userAccessToken = request.directive.payload.scope.token;
+ console.log("DEBUG", "userAccessToken: " + userAccessToken);
+
+ if (!userAccessToken || !isValidToken(userAccessToken)) {
+ const message = "Invalid access token: " + userAccessToken;
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("INVALID_AUTHORIZATION_CREDENTIAL", message, "", ""));
+ return;
+ }
+
+ /**
+ * Retrieve list of devices from cloud based on token.
+ */
+ getDevicesFromAwsIot(userAccessToken, callback);
+}
+
+function handleReportState(request, callback) {
+ console.log("DEBUG", "ReportState Request: " + JSON.stringify(request, null, 2));
+
+ const correlationToken = request.directive.header.correlationToken;
+ console.log("DEBUG", "correlationToken: " + correlationToken);
+
+ const endpointId = request.directive.endpoint.endpointId;
+
+ /**
+ * Get the OAuth token from the request.
+ */
+ const userAccessToken = request.directive.endpoint.scope.token;
+ console.log("DEBUG", "userAccessToken: " + userAccessToken);
+
+ if (!userAccessToken || !isValidToken(userAccessToken)) {
+ const message = "Invalid access token: " + userAccessToken;
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("INVALID_AUTHORIZATION_CREDENTIAL", message, endpointId, correlationToken));
+ return;
+ }
+
+ if (!endpointId) {
+ const message = "No endpointId provided in request";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("NO_SUCH_ENDPOINT", message, endpointId, correlationToken));
+ return;
+ }
+
+ /**
+ * At this point the endpointId and accessToken are present in the request.
+ */
+ if (!isDeviceOnline(endpointId, userAccessToken)) {
+ const message = "Target is offline";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("ENDPOINT_UNREACHABLE", message, endpointId, correlationToken));
+ return;
+ }
+
+ /**
+ * Retrieve device state from cloud.
+ */
+ getDeviceStateFromAwsIot(userAccessToken, endpointId, correlationToken, callback);
+}
+
+function handleControl(request, callback) {
+ console.log("DEBUG", "Control Request: " + JSON.stringify(request, null, 2));
+
+ const correlationToken = request.directive.header.correlationToken;
+ const endpointId = request.directive.endpoint.endpointId;
+
+ /**
+ * Get the access token from the request.
+ */
+ const userAccessToken = request.directive.endpoint.scope.token;
+ console.log("DEBUG", "userAccessToken: " + userAccessToken);
+
+ if (!userAccessToken || !isValidToken(userAccessToken)) {
+ const message = "Invalid access token: " + userAccessToken;
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("INVALID_AUTHORIZATION_CREDENTIAL", message, endpointId, correlationToken));
+ return;
+ }
+
+ if (!endpointId) {
+ const message = "No endpointId provided in request";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("NO_SUCH_ENDPOINT", message, endpointId, correlationToken));
+ return;
+ }
+
+ /**
+ * At this point the endpointId and accessToken are present in the request.
+ */
+ if (!isDeviceOnline(endpointId, userAccessToken)) {
+ const message = "Target is offline";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("ENDPOINT_UNREACHABLE", message, endpointId, correlationToken));
+ return;
+ }
+
+ switch (request.directive.header.name) {
+ case "TurnOn":
+ setAwsIotDeviceState(userAccessToken, endpointId, correlationToken, "ON", null, null, callback);
+ break;
+
+ case "TurnOff":
+ setAwsIotDeviceState(userAccessToken, endpointId, correlationToken, "OFF", null, null, callback);
+ break;
+
+ case "SetBrightness": {
+ const brightness = request.directive.payload.brightness;
+ if (!brightness) {
+ const message = "No brightness provided in request";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("INVALID_VALUE", message, endpointId, correlationToken));
+ return;
+ }
+ setAwsIotDeviceState(userAccessToken, endpointId, correlationToken, null, brightness, null, callback);
+ break;
+ }
+
+ case "AdjustBrightness": {
+ const delta = request.directive.payload.brightnessDelta;
+ if (!delta) {
+ const message = "No brightness delta provided in request";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("INVALID_VALUE", message, endpointId, correlationToken));
+ return;
+ }
+ setAwsIotDeviceState(userAccessToken, endpointId, correlationToken, null, null, delta, callback);
+ break;
+ }
+
+ default: {
+ const message = "Directive not supported";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("INVALID_DIRECTIVE", message, endpointId, correlationToken));
+ }
+ }
+}
+
+/**
+ * Main entry point.
+ * Incoming events from Alexa service through Smart Home API are all handled by this function.
+ */
+exports.handler = (request, context, callback) => {
+ console.log("DEBUG", "Request: " + JSON.stringify(request, null, 2));
+
+ switch (request.directive.header.namespace) {
+ /**
+ * The namespace of 'Alexa.Discovery' indicates a request is being made to the Lambda for
+ * discovering all endpoints associated with the customer's endpoint cloud account.
+ */
+ case "Alexa.Discovery":
+ handleDiscovery(request, callback);
+ break;
+
+ /**
+ * The namespace of "Alexa.PowerController" and "Alexa.BrightnessController" indicates control request
+ */
+ case "Alexa.PowerController":
+ case "Alexa.BrightnessController":
+ handleControl(request, callback);
+ break;
+
+ /**
+ * The namespace of "Alexa" with a name of "ReportState" indicates state request
+ */
+ case "Alexa":
+ if (request.directive.header.name === "ReportState") {
+ handleReportState(request, callback);
+
+ } else {
+ const message = "Directive not supported";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("INVALID_DIRECTIVE", message, "", ""));
+ }
+ break;
+
+ /**
+ * Received an unexpected message
+ */
+ default: {
+ const message = "Namespace not supported";
+ console.log("ERROR", message);
+ callback(null, generateErrorResponse("INVALID_DIRECTIVE", message, "", ""));
+ }
+ }
+};
diff --git a/ocf-light-server/LICENSE.md b/ocf-light-server/LICENSE.md
new file mode 100644
index 0000000..b786745
--- /dev/null
+++ b/ocf-light-server/LICENSE.md
@@ -0,0 +1,195 @@
+Copyright (c) 2017 IoTivity
+<http://www.iotivity.org/>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+<http://www.apache.org/licenses/LICENSE-2.0>
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+```
+-------------------------------------------------------------------------
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+```
diff --git a/ocf-light-server/README.md b/ocf-light-server/README.md
new file mode 100644
index 0000000..bc1dc66
--- /dev/null
+++ b/ocf-light-server/README.md
@@ -0,0 +1,51 @@
+<!---
+ ~ //******************************************************************
+ ~ //
+ ~ // Copyright 2107 Intel Corporation All Rights Reserved.
+ ~ //
+ ~ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ ~ //
+ ~ // Licensed under the Apache License, Version 2.0 (the "License");
+ ~ // you may not use this file except in compliance with the License.
+ ~ // You may obtain a copy of the License at
+ ~ //
+ ~ // http://www.apache.org/licenses/LICENSE-2.0
+ ~ //
+ ~ // Unless required by applicable law or agreed to in writing, software
+ ~ // distributed under the License is distributed on an "AS IS" BASIS,
+ ~ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ // See the License for the specific language governing permissions and
+ ~ // limitations under the License.
+ ~ //
+ ~ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ --->
+
+## Install required build libraries
+
+You will need to build IoTivity prior to use.
+
+ $ scons TARGET_TRANSPORT=IP SECURED=0 BUILD_JAVA=ON
+
+Once built, the build.sh and run.sh scripts expect iotivity.jar to be copied to ./lib directory.
+
+ $ cp <iotivity>/out/linux/x86_64/release/java/iotivity.jar lib/.
+
+## Build
+
+ $ ./build.sh
+
+## Run Command line parameters
+
+You can optionally set the name of the light and its inital on/off state and brightness.
+
+ $ ./run.sh [ lightName [ on | off [ 0 - 100 ] ] ]
+
+For example:
+
+ $ ./run.sh "My Favorite Light" on 75
+
+If no parameters are given, a random light name is generated with power on and brightness 100.
+
+Any OCF client should be able to interact with the light. For example, the Client Controller of the IoTivity Simulator. See https://wiki.iotivity.org/iotivity_tool_guide
+
+
diff --git a/ocf-light-server/build.sh b/ocf-light-server/build.sh
new file mode 100755
index 0000000..25e8464
--- /dev/null
+++ b/ocf-light-server/build.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+#find ./out -type f -name '*.class' -delete
+rm -rf ./out
+mkdir out
+javac @options.txt @sourcefiles.txt
+
+#jar -cfv OcfLightDevice.jar -C out/ .
+#jar -ufv OcfLightDevice.jar res/
+jar -cf OcfLightDevice.jar -C out/ .
+jar -uf OcfLightDevice.jar res/
+
diff --git a/ocf-light-server/options.txt b/ocf-light-server/options.txt
new file mode 100644
index 0000000..ef39293
--- /dev/null
+++ b/ocf-light-server/options.txt
@@ -0,0 +1,2 @@
+-cp ./lib/iotivity.jar
+-d ./out/
diff --git a/ocf-light-server/res/bulb-icon-32x32.png b/ocf-light-server/res/bulb-icon-32x32.png
new file mode 100644
index 0000000..b35091d
--- /dev/null
+++ b/ocf-light-server/res/bulb-icon-32x32.png
Binary files differ
diff --git a/ocf-light-server/res/light-off.png b/ocf-light-server/res/light-off.png
new file mode 100644
index 0000000..2ca1f68
--- /dev/null
+++ b/ocf-light-server/res/light-off.png
Binary files differ
diff --git a/ocf-light-server/res/light-on.png b/ocf-light-server/res/light-on.png
new file mode 100644
index 0000000..5ea4a8e
--- /dev/null
+++ b/ocf-light-server/res/light-on.png
Binary files differ
diff --git a/ocf-light-server/run.sh b/ocf-light-server/run.sh
new file mode 100755
index 0000000..517a993
--- /dev/null
+++ b/ocf-light-server/run.sh
@@ -0,0 +1 @@
+java -Djava.library.path=/home/larrys/work/iotivity-1.3-rel/iotivity/out/linux/x86_64/release -cp OcfLightDevice.jar:./lib/iotivity.jar org.iotivity.base.examples.OcfLightDevice "$1" "$2" $3 $4
diff --git a/ocf-light-server/sourcefiles.txt b/ocf-light-server/sourcefiles.txt
new file mode 100644
index 0000000..6ea9ca4
--- /dev/null
+++ b/ocf-light-server/sourcefiles.txt
@@ -0,0 +1,13 @@
+./src/main/java/org/iotivity/base/examples/OcfLightDevice.java
+./src/main/java/org/iotivity/base/examples/Light.java
+./src/main/java/org/iotivity/base/examples/LightConfig.java
+./src/main/java/org/iotivity/base/examples/Brightness.java
+./src/main/java/org/iotivity/base/examples/Switch.java
+./src/main/java/org/iotivity/base/examples/Resource.java
+./src/main/java/org/iotivity/base/examples/Links.java
+./src/main/java/org/iotivity/base/examples/Link.java
+./src/main/java/org/iotivity/base/examples/LightPanel.java
+./src/main/java/org/iotivity/base/examples/LightImageObserver.java
+./src/main/java/org/iotivity/base/examples/NamesPropertyFile.java
+
+
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/Brightness.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/Brightness.java
new file mode 100644
index 0000000..765cca3
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/Brightness.java
@@ -0,0 +1,103 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.ErrorCode;
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Brightness
+ *
+ * This class represents a rightness resource
+ */
+public class Brightness extends Resource implements LightImageObserver {
+ static public final String RES_TYPE = "oic.r.light.brightness";
+ static public final String RES_IF = "oic.if.a";
+
+ static public final String BRIGHTNESS_KEY = "brightness";
+
+ private int brightness;
+
+ public Brightness(String uuid) {
+ super("/ocf/brightness/" + uuid, RES_TYPE, RES_IF);
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) {
+ try {
+ if (rep.hasAttribute(BRIGHTNESS_KEY)) {
+ brightness = rep.getValue(BRIGHTNESS_KEY);
+ brightness = Math.max(0, brightness);
+ brightness = Math.min(100, brightness);
+ }
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to get representation values");
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() {
+ OcRepresentation rep = new OcRepresentation();
+ try {
+ brightness = Math.max(0, brightness);
+ brightness = Math.min(100, brightness);
+ rep.setValue(BRIGHTNESS_KEY, brightness);
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to set representation values");
+ }
+ return rep;
+ }
+
+ public int getBrightness() {
+ return brightness;
+ }
+
+ public void setBrightness(int brightness) {
+ brightness = Math.max(0, brightness);
+ brightness = Math.min(100, brightness);
+ this.brightness = brightness;
+ }
+
+ @Override
+ public void update(boolean powerOn, int brightness) {
+ setBrightness(brightness);
+ try {
+ OcPlatform.notifyAllObservers(getResourceHandle());
+ } catch (OcException e) {
+ ErrorCode errorCode = e.getErrorCode();
+ if (ErrorCode.NO_OBSERVERS == errorCode) {
+// OcfLightDevice.msg("No observers found");
+ } else {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to notify observers");
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "[" + super.toString() + ", " + BRIGHTNESS_KEY + ": " + brightness + "]";
+ }
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/Light.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/Light.java
new file mode 100644
index 0000000..1926420
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/Light.java
@@ -0,0 +1,259 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.ErrorCode;
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.OcRepresentation;
+import org.iotivity.base.PayloadType;
+
+/**
+ * Light
+ *
+ * This class represents a light resource
+ */
+public class Light extends Resource implements LightImageObserver {
+ static private final String RES_TYPE = "oic.d.light";
+
+ static private final String LINKS_KEY = "links";
+
+ private Links resourceLinks;
+
+ private LightConfig lightConfigRes;
+ private Switch switchRes;
+ private Brightness brightnessRes;
+
+ private String deviceName;
+ private boolean powerOn;
+ private int brightness;
+
+ public Light(boolean useLinks, String name, String uuid, boolean powerOn, int brightness, LightPanel ui) {
+ super("/ocf/light/" + uuid, RES_TYPE, OcPlatform.DEFAULT_INTERFACE);
+
+ if (useLinks) {
+ lightConfigRes = new LightConfig(name, uuid, this);
+ lightConfigRes.addObserver(ui);
+ OcfLightDevice.msg("Created config resource: " + lightConfigRes);
+
+ switchRes = new Switch(uuid);
+ switchRes.setValue(powerOn);
+ switchRes.addObserver(ui);
+ ui.addObserver(switchRes);
+ OcfLightDevice.msg("Created switch resource: " + switchRes);
+
+ brightnessRes = new Brightness(uuid);
+ brightnessRes.setBrightness(brightness);
+ brightnessRes.addObserver(ui);
+ ui.addObserver(brightnessRes);
+ OcfLightDevice.msg("Created brightness resource: " + brightnessRes);
+
+ } else {
+ deviceName = name;
+ this.powerOn = powerOn;
+ this.brightness = brightness;
+ addObserver(ui);
+ ui.addObserver(this);
+ }
+
+ try {
+ OcPlatform.setPropertyValue(PayloadType.PLATFORM.getValue(), "mnmn", "Intel");
+
+ setDeviceName(name);
+ OcPlatform.setPropertyValue(PayloadType.DEVICE.getValue(), "icv", "ocf.1.0.0");
+ OcPlatform.setPropertyValue(PayloadType.DEVICE.getValue(), "dmv", "ocf.res.1.0.0,ocf.sh.1.0.0");
+
+ } catch (OcException e) {
+ OcfLightDevice.msgError("Failed to create properties for " + getResourceUri());
+ e.printStackTrace();
+ }
+
+ if (useLinks) {
+ Link[] links = new Link[3];
+ links[0] = new Link(lightConfigRes.getResourceUri(), new String[] { LightConfig.RES_TYPE });
+ links[1] = new Link(switchRes.getResourceUri(), new String[] { Switch.RES_TYPE });
+ links[2] = new Link(brightnessRes.getResourceUri(), new String[] { Brightness.RES_TYPE });
+ resourceLinks = new Links(links);
+
+ try {
+ OcPlatform.bindInterfaceToResource(getResourceHandle(), OcPlatform.LINK_INTERFACE);
+
+ } catch (OcException e) {
+ OcfLightDevice.msgError("Failed to bind link interface for " + getResourceUri());
+ e.printStackTrace();
+ }
+
+ } else {
+ try {
+ OcPlatform.bindInterfaceToResource(getResourceHandle(), LightConfig.RES_IF);
+ OcPlatform.bindTypeToResource(getResourceHandle(), LightConfig.RES_TYPE);
+
+ OcPlatform.bindInterfaceToResource(getResourceHandle(), Switch.RES_IF);
+ OcPlatform.bindTypeToResource(getResourceHandle(), Switch.RES_TYPE);
+
+ OcPlatform.bindInterfaceToResource(getResourceHandle(), Brightness.RES_IF);
+ OcPlatform.bindTypeToResource(getResourceHandle(), Brightness.RES_TYPE);
+
+ } catch (OcException e) {
+ OcfLightDevice.msgError("Failed to bind interface or type for " + getResourceUri());
+ e.printStackTrace();
+ }
+
+ }
+
+ OcfLightDevice.msg("Created light resource: " + this);
+ }
+
+ public void unregister() {
+ try {
+ lightConfigRes.unregisterResource();
+ } catch (OcException e) {
+ OcfLightDevice.msgError("Failed to unregister " + lightConfigRes.getResourceUri());
+ e.printStackTrace();
+ }
+ try {
+ switchRes.unregisterResource();
+ } catch (OcException e) {
+ OcfLightDevice.msgError("Failed to unregister " + switchRes.getResourceUri());
+ e.printStackTrace();
+ }
+ try {
+ brightnessRes.unregisterResource();
+ } catch (OcException e) {
+ OcfLightDevice.msgError("Failed to unregister " + brightnessRes.getResourceUri());
+ e.printStackTrace();
+ }
+ try {
+ unregisterResource();
+ } catch (OcException e) {
+ OcfLightDevice.msgError("Failed to unregister " + getResourceUri());
+ e.printStackTrace();
+ }
+ }
+
+ public void setDeviceName(String name) {
+ try {
+ OcPlatform.setPropertyValue(PayloadType.DEVICE.getValue(), "n", name);
+
+ } catch (OcException e) {
+ OcfLightDevice.msgError("Failed to set device name to " + name);
+ e.printStackTrace();
+ }
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) {
+ try {
+ if (rep.hasAttribute(LINKS_KEY)) {
+ OcRepresentation[] links = rep.getValue(LINKS_KEY);
+ resourceLinks.setOcRepresentation(links);
+ }
+ if (rep.hasAttribute(LightConfig.NAME_KEY_SIM)) {
+ deviceName = rep.getValue(LightConfig.NAME_KEY_SIM);
+ setDeviceName(deviceName);
+ }
+ if (rep.hasAttribute(LightConfig.NAME_KEY)) {
+ deviceName = rep.getValue(LightConfig.NAME_KEY);
+ setDeviceName(deviceName);
+ }
+ if (rep.hasAttribute(Switch.VALUE_KEY)) {
+ powerOn = rep.getValue(Switch.VALUE_KEY);
+ }
+ if (rep.hasAttribute(Brightness.BRIGHTNESS_KEY)) {
+ brightness = rep.getValue(Brightness.BRIGHTNESS_KEY);
+ brightness = Math.max(0, brightness);
+ brightness = Math.min(100, brightness);
+ }
+
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to get representation values");
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() {
+ OcRepresentation rep = new OcRepresentation();
+ try {
+ if (resourceLinks != null) {
+ OcRepresentation[] links = resourceLinks.getOcRepresentation();
+ rep.setValue(LINKS_KEY, links);
+
+ } else {
+ rep.setValue(LightConfig.NAME_KEY, deviceName);
+ rep.setValue(LightConfig.NAME_KEY_SIM, deviceName);
+
+ rep.setValue(Switch.VALUE_KEY, powerOn);
+
+ brightness = Math.max(0, brightness);
+ brightness = Math.min(100, brightness);
+ rep.setValue(Brightness.BRIGHTNESS_KEY, brightness);
+ }
+
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to set representation values");
+ }
+
+ return rep;
+ }
+
+ public String getDeviceName() {
+ return deviceName;
+ }
+
+ public boolean getPowerOn() {
+ return powerOn;
+ }
+
+ public int getBrightness() {
+ return brightness;
+ }
+
+ @Override
+ public void update(boolean powerOn, int brightness) {
+ this.powerOn = powerOn;
+ this.brightness = brightness;
+
+ try {
+ OcPlatform.notifyAllObservers(getResourceHandle());
+ } catch (OcException e) {
+ ErrorCode errorCode = e.getErrorCode();
+ if (ErrorCode.NO_OBSERVERS == errorCode) {
+// OcfLightDevice.msg("No observers found");
+ } else {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to notify observers");
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (resourceLinks != null) {
+ return "[" + super.toString() + ", " + resourceLinks + "]";
+
+ } else {
+ return "[" + super.toString() + ", " + LightConfig.NAME_KEY + ": " + deviceName + ", "
+ + Switch.VALUE_KEY + ": " + powerOn + ", " + Brightness.BRIGHTNESS_KEY + ": " + brightness + "]";
+ }
+ }
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/LightConfig.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/LightConfig.java
new file mode 100644
index 0000000..3758dfd
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/LightConfig.java
@@ -0,0 +1,86 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * LightConfig
+ *
+ * This class represents a light configuration resource
+ */
+public class LightConfig extends Resource {
+ static public final String RES_TYPE = "oic.wk.con";
+ static public final String RES_IF = "oic.if.rw";
+
+ static public final String NAME_KEY = "n";
+ static public final String NAME_KEY_SIM = "nn"; // using 'nn' so it can be used in the simulator
+
+ private String deviceName;
+ private Light lightToConfig; // the light to be configured
+
+ public LightConfig(String name, String uuid, Light light) {
+ super("/ocf/light-config/" + uuid, RES_TYPE, RES_IF);
+ deviceName = name;
+ lightToConfig = light;
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) {
+ try {
+ if (rep.hasAttribute(NAME_KEY_SIM)) {
+ deviceName = rep.getValue(NAME_KEY_SIM);
+ lightToConfig.setDeviceName(deviceName);
+ }
+ if (rep.hasAttribute(NAME_KEY)) {
+ deviceName = rep.getValue(NAME_KEY);
+ lightToConfig.setDeviceName(deviceName);
+ }
+
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to get representation values");
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() {
+ OcRepresentation rep = new OcRepresentation();
+ try {
+ rep.setValue(NAME_KEY, deviceName);
+ rep.setValue(NAME_KEY_SIM, deviceName);
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to set representation values");
+ }
+ return rep;
+ }
+
+ public String getDeviceName() {
+ return deviceName;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + super.toString() + ", " + NAME_KEY + ": " + deviceName + "]";
+ }
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/LightImageObserver.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/LightImageObserver.java
new file mode 100644
index 0000000..125b716
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/LightImageObserver.java
@@ -0,0 +1,31 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2017 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+/**
+ * LightImageObserver
+ */
+public interface LightImageObserver {
+
+ void update(boolean powerOn, int brightness);
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/LightPanel.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/LightPanel.java
new file mode 100644
index 0000000..6c52de8
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/LightPanel.java
@@ -0,0 +1,213 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import java.awt.AlphaComposite;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.imageio.ImageIO;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * LightPanel
+ */
+public class LightPanel extends JLabel implements Observer {
+
+ private boolean powerOn;
+ private int brightness;
+
+ private BufferedImage imageOn;
+ private BufferedImage imageOff;
+ private BufferedImage composite;
+
+ public LightPanel(boolean powerOn, int brightness) {
+
+ this.powerOn = powerOn;
+ this.brightness = brightness;
+
+ try {
+ imageOn = ImageIO.read(LightPanel.class.getResource("/res/light-on.png"));
+ imageOff = ImageIO.read(LightPanel.class.getResource("/res/light-off.png"));
+
+ composite = new BufferedImage(imageOff.getWidth(), imageOff.getHeight(), BufferedImage.TYPE_INT_ARGB);
+
+ Graphics g = composite.getGraphics();
+ g.drawImage(imageOff, 0, 0, null);
+
+ float alpha = powerOn ? ((float) brightness / 100.0f) : 0.0f;
+ AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
+ ((Graphics2D) g).setComposite(ac);
+ g.drawImage(imageOn, 0, 0, null);
+
+ ImageIcon imageIcon = new ImageIcon(composite);
+ setIcon(imageIcon);
+
+ setComponentPopupMenu(new SettingsPopupMenu(this));
+
+ } catch (IOException e) {
+ OcfLightDevice.msgError("Error creating light image: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void paintComponent(Graphics g) {
+ super.paintComponent(g);
+
+ g.drawImage(imageOff, 0, 0, null);
+
+ float alpha = powerOn ? ((float) brightness / 100.0f) : 0.0f;
+ AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
+ ((Graphics2D) g).setComposite(ac);
+ g.drawImage(imageOn, 0, 0, null);
+ }
+
+ @Override
+ public void update(Observable o, Object arg) {
+ boolean repaintRequired = false;
+ if (o instanceof Switch) {
+ powerOn = ((Switch) o).getValue();
+ SettingsPopupMenu popupMenu = (SettingsPopupMenu) getComponentPopupMenu();
+ popupMenu.setPowerOn(powerOn);
+ repaintRequired = true;
+
+ } else if (o instanceof Brightness) {
+ brightness = ((Brightness) o).getBrightness();
+ SettingsPopupMenu popupMenu = (SettingsPopupMenu) getComponentPopupMenu();
+ popupMenu.setBrightness(brightness);
+ repaintRequired = true;
+
+ } else if (o instanceof LightConfig) {
+ String deviceName = ((LightConfig) o).getDeviceName();
+ JFrame frame = (JFrame) SwingUtilities.getWindowAncestor(this);
+ frame.setTitle(deviceName);
+
+ } else if (o instanceof Light) {
+ String deviceName = ((Light) o).getDeviceName();
+ powerOn = ((Light) o).getPowerOn();
+ brightness = ((Light) o).getBrightness();
+
+ JFrame frame = (JFrame) SwingUtilities.getWindowAncestor(this);
+ frame.setTitle(deviceName);
+
+ SettingsPopupMenu popupMenu = (SettingsPopupMenu) getComponentPopupMenu();
+ popupMenu.setPowerOn(powerOn);
+ popupMenu.setBrightness(brightness);
+ repaintRequired = true;
+
+ } else {
+ // ignore
+ }
+
+ if (repaintRequired) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ repaint();
+ }
+ });
+ }
+ }
+
+ // LightImageObservable implementation
+ private Map<Integer, LightImageObserver> observers = new ConcurrentHashMap<Integer, LightImageObserver>();
+
+ public void addObserver(LightImageObserver observer) {
+ observers.put(observer.hashCode(), observer);
+ }
+
+ public void notifyObservers() {
+ Thread observerNotifier = new Thread(new Runnable() {
+ public void run() {
+ for (LightImageObserver observer : observers.values()) {
+ observer.update(powerOn, brightness);
+ }
+ }
+ });
+ observerNotifier.setDaemon(true);
+ observerNotifier.start();
+ }
+
+ private class SettingsPopupMenu extends JPopupMenu {
+ private JCheckBoxMenuItem powerItem;
+ private JMenuItem brightnessItem;
+ private SpinnerNumberModel model;
+
+ public SettingsPopupMenu(final LightPanel lightPanel) {
+ powerItem = new JCheckBoxMenuItem("On");
+ powerItem.setSelected(lightPanel.powerOn);
+ powerItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ lightPanel.powerOn = powerItem.isSelected();
+ lightPanel.repaint();
+ lightPanel.notifyObservers();
+ }
+ });
+ add(powerItem);
+
+ brightnessItem = new JMenuItem();
+ model = new SpinnerNumberModel(lightPanel.brightness, 0, 100, 1);
+ JSpinner spinner = new JSpinner(model);
+ brightnessItem.add(spinner);
+
+ brightnessItem.setPreferredSize(powerItem.getPreferredSize());
+ spinner.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ lightPanel.brightness = (int) model.getValue();
+ lightPanel.repaint();
+ lightPanel.notifyObservers();
+ }
+ });
+ add(brightnessItem);
+ }
+
+ public void setPowerOn(boolean powerOn) {
+ powerItem.setSelected(powerOn);
+ }
+
+ public void setBrightness(int brightness) {
+ model.setValue(brightness);
+ }
+ }
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/Link.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/Link.java
new file mode 100644
index 0000000..aa36586
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/Link.java
@@ -0,0 +1,90 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2017 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Link
+ */
+public class Link {
+
+ static private final String HREF_KEY = "href";
+ static private final String REL_KEY = "rel";
+ static private final String RT_KEY = "rt";
+ static private final String DEFAULT_REL = "contains";
+
+ private String href;
+ private String rel;
+ private String[] rt;
+
+ public Link(String href, String[] rt) {
+ this(href, DEFAULT_REL, rt);
+ }
+
+ public Link(String href, String rel, String[] rt) {
+ this.href = href;
+ this.rel = rel;
+ this.rt = rt;
+ }
+
+ public void setOcRepresentation(OcRepresentation ocRep) throws OcException {
+ if (ocRep.hasAttribute(HREF_KEY)) {
+ href = ocRep.getValue(HREF_KEY);
+ }
+ if (ocRep.hasAttribute(REL_KEY)) {
+ rel = ocRep.getValue(REL_KEY);
+ }
+ if (ocRep.hasAttribute(RT_KEY)) {
+ rt = ocRep.getValue(RT_KEY);
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() throws OcException {
+ OcRepresentation ocRep = new OcRepresentation();
+ ocRep.setValue(HREF_KEY, href);
+ ocRep.setValue(REL_KEY, rel);
+ ocRep.setValue(RT_KEY, rt);
+ return ocRep;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ boolean first = true;
+ for (String type : rt) {
+ if (!first) {
+ sb.append(", ");
+ }
+ if (type != null) {
+ sb.append(type.toString());
+ }
+ first = false;
+ }
+ sb.append("]");
+
+ return "[" + HREF_KEY + ": " + href + ", " + REL_KEY + ": " + rel + ", " + RT_KEY + ": " + sb + "]";
+ }
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/Links.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/Links.java
new file mode 100644
index 0000000..7891a9a
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/Links.java
@@ -0,0 +1,82 @@
+/*
+ * //******************************************************************
+ * //
+ * // Copyright 2017 Intel Corporation All Rights Reserved.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ * //
+ * // Licensed under the Apache License, Version 2.0 (the "License");
+ * // you may not use this file except in compliance with the License.
+ * // You may obtain a copy of the License at
+ * //
+ * // http://www.apache.org/licenses/LICENSE-2.0
+ * //
+ * // Unless required by applicable law or agreed to in writing, software
+ * // distributed under the License is distributed on an "AS IS" BASIS,
+ * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * // See the License for the specific language governing permissions and
+ * // limitations under the License.
+ * //
+ * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Links
+ */
+public class Links {
+
+ public static final String LINKS_KEY = "links";
+
+ private Link[] links;
+
+ public Links(Link[] links) {
+ this.links = (links != null) ? links : new Link[0];
+ }
+
+ public void setOcRepresentation(OcRepresentation[] ocRepLinks) throws OcException {
+ if ((ocRepLinks != null) && (ocRepLinks.length > 0)) {
+ links = new Link[ocRepLinks.length];
+ int index = 0;
+ for (OcRepresentation ocRepLink : ocRepLinks) {
+ links[index] = new Link("", new String[0]);
+ links[index].setOcRepresentation(ocRepLink);
+ ++index;
+ }
+ }
+ }
+
+ public OcRepresentation[] getOcRepresentation() throws OcException {
+ OcRepresentation[] ocRepLinks = new OcRepresentation[links.length];
+ int index = 0;
+ for (Link link : links) {
+ OcRepresentation ocRepLink = link.getOcRepresentation();
+ ocRepLinks[index] = ocRepLink;
+ ++index;
+ }
+ return ocRepLinks;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ boolean first = true;
+ for (Link link : links) {
+ if (!first) {
+ sb.append(", ");
+ }
+ if (link != null) {
+ sb.append(link.toString());
+ }
+ first = false;
+ }
+ sb.append("]");
+
+ return sb.toString();
+ }
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java
new file mode 100644
index 0000000..174fddb
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java
@@ -0,0 +1,115 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * This class encapsulates the names property file. The names property file is
+ * used for obtaining the uuid for previously used light names.
+ */
+public class NamesPropertyFile {
+
+ static private Properties namesProperties;
+ static private File namesPropertyFile;
+
+ static private NamesPropertyFile instance;
+
+ static {
+ try {
+ namesProperties = new Properties();
+ namesPropertyFile = new File("names.prop");
+ instance = new NamesPropertyFile();
+
+ } catch (Exception e) {
+ OcfLightDevice.msgError("Error creating names property file instance.");
+ }
+ }
+
+ private NamesPropertyFile() {
+ // read the names property file
+ FileInputStream inStream = null;
+ try {
+ if (namesPropertyFile.exists() && namesPropertyFile.length() > 0) {
+ inStream = new FileInputStream(namesPropertyFile);
+ namesProperties.loadFromXML(inStream);
+ namesProperties.list(System.out);
+ }
+
+ } catch (IOException e) {
+ OcfLightDevice.msgError("Error loading name properties: " + e.toString());
+ e.printStackTrace();
+
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ OcfLightDevice.msgError("Error closing name properties file: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static NamesPropertyFile getInstance() {
+ return instance;
+ }
+
+ public boolean hasName(String name) {
+ return namesProperties.containsKey(name);
+ }
+
+ public String getUuidForName(String name) {
+ return (String) namesProperties.get(name);
+ }
+
+ public void updateNamesProperty(String name, String uuid) {
+ // update names property file
+ namesProperties.put(name, uuid);
+ FileOutputStream outStream = null;
+ try {
+ outStream = new FileOutputStream(namesPropertyFile);
+ namesProperties.storeToXML(outStream, null);
+
+ } catch (IOException e) {
+ OcfLightDevice.msgError("Error storing name properties: " + e.toString());
+ e.printStackTrace();
+ }
+
+ finally {
+ if (outStream != null) {
+ try {
+ outStream.close();
+ } catch (IOException e) {
+ OcfLightDevice.msgError("Error closing name properties file: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/OcfLightDevice.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/OcfLightDevice.java
new file mode 100644
index 0000000..0c05b26
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/OcfLightDevice.java
@@ -0,0 +1,203 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.ModeType;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.PlatformConfig;
+import org.iotivity.base.QualityOfService;
+import org.iotivity.base.ServiceType;
+
+import java.awt.FlowLayout;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.UUID;
+
+import javax.imageio.ImageIO;
+import javax.swing.JFrame;
+import javax.swing.WindowConstants;
+
+/**
+ * OcfLightDevice
+ */
+public class OcfLightDevice {
+
+ static Light light;
+
+ static boolean isTest;
+ static int testFrequency = 3;
+
+ static boolean useLinks;
+ static String name;
+ static boolean powerOn = true;
+ static int brightness = 100;
+
+ public static void main(String args[]) throws IOException, InterruptedException {
+
+ if ((args.length > 0) && (args[0].startsWith("-"))) {
+ if (args[0].startsWith("-t")) {
+ isTest = true;
+ try {
+ testFrequency = Integer.valueOf(args[0].substring(2));
+ } catch (NumberFormatException e) {
+ msg("Frequency must be an integer in the range (1, 60), using default 3.");
+ }
+ testFrequency = Math.max(1, testFrequency);
+ testFrequency = Math.min(60, testFrequency);
+ msg("Server in test mode with frequecy of " + testFrequency);
+ } else if (args[0].equalsIgnoreCase("-l")) {
+ useLinks = true;
+ msg("Server using links");
+ } else {
+ msg("Unknown runtime parameter: " + args[0]);
+ }
+ parseNameAndInitialSettings(args, 1);
+
+ } else {
+ parseNameAndInitialSettings(args, 0);
+ }
+
+ PlatformConfig platformConfig = new PlatformConfig(ServiceType.IN_PROC, ModeType.SERVER, "0.0.0.0", 0,
+ QualityOfService.LOW);
+
+ OcPlatform.Configure(platformConfig);
+ msg("Platform configured");
+
+ String uuid = null;
+ if (NamesPropertyFile.getInstance().hasName(name)) {
+ uuid = NamesPropertyFile.getInstance().getUuidForName(name);
+ } else {
+ uuid = UUID.randomUUID().toString();
+ NamesPropertyFile.getInstance().updateNamesProperty(name, uuid);
+ }
+
+ JFrame frame = new JFrame(name);
+ frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+
+ try {
+ frame.setIconImage(ImageIO.read(OcfLightDevice.class.getResource("/res/bulb-icon-32x32.png")));
+ } catch (IOException ioe) {
+ msgError("Error loading application icon: " + ioe.toString());
+ ioe.printStackTrace();
+ }
+
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ if (light != null) {
+// light.unregister();
+ }
+ msg("Shutdown");
+ e.getWindow().dispose();
+ System.exit(0);
+ }
+ });
+
+ frame.setResizable(false);
+ frame.setLayout(new FlowLayout());
+
+ LightPanel lightPanel = new LightPanel(powerOn, brightness);
+ light = new Light(useLinks, name, uuid, powerOn, brightness, lightPanel);
+
+ frame.setContentPane(lightPanel);
+ frame.pack();
+ frame.setVisible(true);
+
+ if (isTest) {
+ // Start running a task to toggle the light and change its brightness
+ Timer timer = new Timer();
+ timer.schedule(new ToggleTask(lightPanel), testFrequency * 1000, testFrequency * 1000);
+ }
+ }
+
+ private static void parseNameAndInitialSettings(String args[], int index) {
+ if (args.length > index) {
+ name = args[index];
+ }
+
+ if (args.length > index + 1) {
+ String arg = args[index + 1];
+ if (!arg.isEmpty()) {
+ powerOn = arg.equalsIgnoreCase("true") || arg.equalsIgnoreCase("on") || arg.equalsIgnoreCase("yes")
+ || arg.equals("1");
+ }
+ }
+
+ if (args.length > index + 2) {
+ try {
+ brightness = Integer.valueOf(args[index + 2]);
+ } catch (NumberFormatException e) {
+ msg("Brightness must be an integer in the range (0, 100), using default 100.");
+ }
+
+ brightness = Math.max(0, brightness);
+ brightness = Math.min(100, brightness);
+ }
+
+ if (name == null || name.isEmpty()) {
+ name = "Light " + (System.currentTimeMillis() % 10000);
+ }
+ }
+
+ private static void sleep(int seconds) {
+ try {
+ Thread.sleep(seconds * 1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ msgError(e.toString());
+ }
+ }
+
+ public static void msg(final String text) {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+ Date date = new Date();
+ System.out.println(dateFormat.format(date) + " " + text);
+ }
+
+ public static void msgError(final String text) {
+ msg("[Error] " + text);
+ }
+
+ public static class ToggleTask extends TimerTask {
+ LightPanel lightPanel;
+
+ public ToggleTask(LightPanel lightPanel) {
+ this.lightPanel = lightPanel;
+ }
+
+ @Override
+ public void run() {
+ boolean powerOn = ! light.getPowerOn();
+ int brightness = (light.getBrightness() + 10) % 101;
+ OcfLightDevice.msg("Notifying observers for resource " + light.toString());
+ light.update(powerOn, brightness);
+ lightPanel.update(light, null);
+ }
+ }
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/Resource.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/Resource.java
new file mode 100644
index 0000000..8262c94
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/Resource.java
@@ -0,0 +1,240 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.EntityHandlerResult;
+import org.iotivity.base.ErrorCode;
+import org.iotivity.base.ObservationInfo;
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.OcRepresentation;
+import org.iotivity.base.OcResourceHandle;
+import org.iotivity.base.OcResourceRequest;
+import org.iotivity.base.OcResourceResponse;
+import org.iotivity.base.RequestHandlerFlag;
+import org.iotivity.base.RequestType;
+import org.iotivity.base.ResourceProperty;
+
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Observable;
+
+/**
+ * Resource
+ *
+ * This is the base class for all resources
+ */
+
+abstract public class Resource extends Observable implements OcPlatform.EntityHandler {
+
+ private String resUri;
+ private OcResourceHandle resHandle;
+
+ public Resource(String uri, String resType, String resIf) {
+ resUri = uri;
+
+ try {
+ resHandle = OcPlatform.registerResource(resUri, resType, resIf, this,
+ EnumSet.of(ResourceProperty.DISCOVERABLE, ResourceProperty.OBSERVABLE, ResourceProperty.SECURE));
+
+ } catch (OcException e) {
+ OcfLightDevice.msgError("Failed to create resource " + resUri);
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public synchronized EntityHandlerResult handleEntity(final OcResourceRequest request) {
+ EntityHandlerResult ehResult = EntityHandlerResult.ERROR;
+ if (null == request) {
+ OcfLightDevice.msg("Server request is invalid");
+ return ehResult;
+ }
+ // Get the request flags
+ EnumSet<RequestHandlerFlag> requestFlags = request.getRequestHandlerFlagSet();
+ if (requestFlags.contains(RequestHandlerFlag.INIT)) {
+ OcfLightDevice.msg("Request Flag: Init for " + request.getResourceUri());
+ ehResult = EntityHandlerResult.OK;
+ }
+ if (requestFlags.contains(RequestHandlerFlag.REQUEST)) {
+// OcfLightDevice.msg("Request Flag: Request for " + request.getResourceUri());
+ ehResult = handleRequest(request);
+ }
+ if (requestFlags.contains(RequestHandlerFlag.OBSERVER)) {
+// OcfLightDevice.msg("Request Flag: Observer for " + request.getResourceUri());
+ ehResult = handleObserver(request);
+ }
+ return ehResult;
+ }
+
+ private EntityHandlerResult handleRequest(OcResourceRequest request) {
+ EntityHandlerResult ehResult = EntityHandlerResult.ERROR;
+ // Check for query params (if any)
+ Map<String, String> queries = request.getQueryParameters();
+// if (!queries.isEmpty()) {
+// OcfLightDevice.msg("Query processing is up to entityHandler");
+// } else {
+// OcfLightDevice.msg("No query parameters in this request");
+// }
+
+ for (Map.Entry<String, String> entry : queries.entrySet()) {
+// OcfLightDevice.msg("Query key: " + entry.getKey() + " value: " + entry.getValue());
+ }
+
+ // Get the request type
+ RequestType requestType = request.getRequestType();
+ switch (requestType) {
+ case GET:
+// OcfLightDevice.msg("Request Type is GET for " + request.getResourceUri());
+ ehResult = handleGetRequest(request);
+ break;
+ case PUT:
+// OcfLightDevice.msg("Request Type is PUT for " + request.getResourceUri());
+ ehResult = handlePutRequest(request);
+ break;
+ case POST:
+// OcfLightDevice.msg("Request Type is POST for " + request.getResourceUri());
+ ehResult = handlePutRequest(request); // same as put
+ break;
+ case DELETE:
+ OcfLightDevice.msg("Request Type is DELETE for " + request.getResourceUri());
+ ehResult = handleDeleteRequest();
+ break;
+ }
+ return ehResult;
+ }
+
+ private EntityHandlerResult handleGetRequest(final OcResourceRequest request) {
+ OcResourceResponse response = new OcResourceResponse();
+ response.setRequestHandle(request.getRequestHandle());
+ response.setResourceHandle(request.getResourceHandle());
+ response.setResponseResult(EntityHandlerResult.OK);
+ response.setResourceRepresentation(getOcRepresentation());
+ return sendResponse(response);
+ }
+
+ private EntityHandlerResult handlePutRequest(final OcResourceRequest request) {
+ OcResourceResponse response = new OcResourceResponse();
+ response.setRequestHandle(request.getRequestHandle());
+ response.setResourceHandle(request.getResourceHandle());
+
+ setOcRepresentation(request.getResourceRepresentation());
+ response.setResourceRepresentation(getOcRepresentation());
+ response.setResponseResult(EntityHandlerResult.OK);
+
+ // notify on separate thread
+ Thread observerNotifier = new Thread(new Runnable() {
+ public void run() {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
+ notifyObservers(request);
+
+ // notify observers (ie implementors of Observer)
+ setChanged();
+ notifyObservers();
+ }
+ });
+ observerNotifier.setDaemon(true);
+ observerNotifier.start();
+
+ return sendResponse(response);
+ }
+
+ private EntityHandlerResult handleDeleteRequest() {
+ try {
+ unregisterResource();
+ return EntityHandlerResult.RESOURCE_DELETED;
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to unregister resource " + resUri);
+ return EntityHandlerResult.ERROR;
+ }
+ }
+
+ private EntityHandlerResult handleObserver(final OcResourceRequest request) {
+ ObservationInfo observationInfo = request.getObservationInfo();
+ switch (observationInfo.getObserveAction()) {
+ case REGISTER:
+// OcfLightDevice.msg("handleObserver register observer " + String.format("%02x", observationInfo.getOcObservationId()));
+ break;
+ case UNREGISTER:
+// OcfLightDevice.msg("handleObserver unregister observer " + String.format("%02x", observationInfo.getOcObservationId()));
+ break;
+ }
+ return EntityHandlerResult.OK;
+ }
+
+ private void notifyObservers(OcResourceRequest request) {
+ OcfLightDevice.msg("Notifying observers for resource " + this);
+ try {
+ OcPlatform.notifyAllObservers(getResourceHandle());
+ } catch (OcException e) {
+ ErrorCode errorCode = e.getErrorCode();
+ if (ErrorCode.NO_OBSERVERS == errorCode) {
+// OcfLightDevice.msg("No observers found");
+ } else {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to notify observers");
+ }
+ }
+ }
+
+ private EntityHandlerResult sendResponse(OcResourceResponse response) {
+ try {
+ OcPlatform.sendResponse(response);
+ return EntityHandlerResult.OK;
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to send response");
+ return EntityHandlerResult.ERROR;
+ }
+ }
+
+ public synchronized void unregisterResource() throws OcException {
+ if (null != resHandle) {
+ OcPlatform.unregisterResource(resHandle);
+ OcfLightDevice.msg("Unregistered resource " + resUri);
+ }
+ }
+
+ public abstract void setOcRepresentation(OcRepresentation rep);
+
+ public abstract OcRepresentation getOcRepresentation();
+
+ public String getResourceUri() {
+ return resUri;
+ }
+
+ public OcResourceHandle getResourceHandle() {
+ return resHandle;
+ }
+
+ @Override
+ public String toString() {
+ return resUri;
+ }
+}
diff --git a/ocf-light-server/src/main/java/org/iotivity/base/examples/Switch.java b/ocf-light-server/src/main/java/org/iotivity/base/examples/Switch.java
new file mode 100644
index 0000000..c2adcbe
--- /dev/null
+++ b/ocf-light-server/src/main/java/org/iotivity/base/examples/Switch.java
@@ -0,0 +1,97 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2017 Intel Corporation.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ */
+
+package org.iotivity.base.examples;
+
+import org.iotivity.base.ErrorCode;
+import org.iotivity.base.OcException;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.OcRepresentation;
+
+/**
+ * Switch
+ *
+ * This class represents a binary switch resource
+ */
+public class Switch extends Resource implements LightImageObserver {
+ static public final String RES_TYPE = "oic.r.switch.binary";
+ static public final String RES_IF = "oic.if.a";
+
+ static public final String VALUE_KEY = "value";
+
+ private boolean powerOn;
+
+ public Switch(String uuid) {
+ super("/ocf/switch/" + uuid, RES_TYPE, RES_IF);
+ }
+
+ public void setOcRepresentation(OcRepresentation rep) {
+ try {
+ if (rep.hasAttribute(VALUE_KEY)) {
+ powerOn = rep.getValue(VALUE_KEY);
+ }
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to get representation values");
+ }
+ }
+
+ public OcRepresentation getOcRepresentation() {
+ OcRepresentation rep = new OcRepresentation();
+ try {
+ rep.setValue(VALUE_KEY, powerOn);
+ } catch (OcException e) {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to set representation values");
+ }
+ return rep;
+ }
+
+ public boolean getValue() {
+ return powerOn;
+ }
+
+ public void setValue(boolean value) {
+ powerOn = value;
+ }
+
+ @Override
+ public void update(boolean powerOn, int brightness) {
+ setValue(powerOn);
+ try {
+ OcPlatform.notifyAllObservers(getResourceHandle());
+ } catch (OcException e) {
+ ErrorCode errorCode = e.getErrorCode();
+ if (ErrorCode.NO_OBSERVERS == errorCode) {
+// OcfLightDevice.msg("No observers found");
+ } else {
+ OcfLightDevice.msgError(e.toString());
+ OcfLightDevice.msgError("Failed to notify observers");
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "[" + super.toString() + ", " + VALUE_KEY + ": " + powerOn + "]";
+ }
+}