Java example of OCF Light Server 39/24539/14
authorLarry Sachs <larry.j.sachs@intel.com>
Mon, 2 Apr 2018 22:32:27 +0000 (15:32 -0700)
committerRick Bell <richard.s.bell@intel.com>
Thu, 19 Apr 2018 18:28:13 +0000 (18:28 +0000)
Change-Id: Ia1583c9dbea61572f0cb1a3fa4bfcf3962ebfcec
Signed-off-by: Larry Sachs <larry.j.sachs@intel.com>
18 files changed:
java/examples-java/SConscript
java/examples-java/ocflightserver/MANIFEST.MF [new file with mode: 0644]
java/examples-java/ocflightserver/SConscript [new file with mode: 0644]
java/examples-java/ocflightserver/run.sh [new file with mode: 0755]
java/examples-java/ocflightserver/src/main/assets/PICS.json [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/assets/ocflightserver_introspection.dat [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/assets/ocflightserver_introspection.json [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/assets/ocflightserver_security.dat [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/assets/ocflightserver_security.json [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Dimming.java [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Light.java [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/LightControlDimmingObserver.java [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/LightControlPanel.java [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/LightControlSwitchObserver.java [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/OcfLightServer.java [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Resource.java [new file with mode: 0644]
java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Switch.java [new file with mode: 0644]

index da85f05..7ac6933 100644 (file)
@@ -29,4 +29,7 @@ jdk_env.SConscript('simpleserver/SConscript', exports='jdk_env')
 jdk_env.SConscript('simpleclient/SConscript', exports='jdk_env')
 
 # Build simpleclientserver sample
-jdk_env.SConscript('simpleclientserver/SConscript', exports='jdk_env')
\ No newline at end of file
+jdk_env.SConscript('simpleclientserver/SConscript', exports='jdk_env')
+
+# Build ocflightserver sample
+jdk_env.SConscript('ocflightserver/SConscript', exports='jdk_env')
diff --git a/java/examples-java/ocflightserver/MANIFEST.MF b/java/examples-java/ocflightserver/MANIFEST.MF
new file mode 100644 (file)
index 0000000..896a9e9
--- /dev/null
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0\r
+Class-Path: iotivity.jar\r
+Main-Class: org.iotivity.base.examples.OcfLightServer\r
diff --git a/java/examples-java/ocflightserver/SConscript b/java/examples-java/ocflightserver/SConscript
new file mode 100644 (file)
index 0000000..f70551f
--- /dev/null
@@ -0,0 +1,39 @@
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Copyright 2018 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.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+Import('jdk_env')
+
+# Build ocflightserver sample
+ocflightserver_classes = jdk_env.Java(target='classes',
+                                     source=['src/main/java'])
+# jdk_env.Jar(target='ocflightserver.jar',
+#             source=[ocflightserver_classes, 'MANIFEST.MF'])
+# SCons is incorrectly calculating the output classes for ocflightserver sample.
+# The following is a work around for the build command above. The unfortunate
+# side effect of this work around results in a larger output.
+example_jar = jdk_env.Jar(target='ocflightserver.jar',
+            source=['classes', File('MANIFEST.MF')],
+            JARCHDIR='$SOURCE')
+jdk_env.Install("../..", example_jar)
+jdk_env.Install(target="../..", source=['src/main/assets/ocflightserver_security.dat'])
+jdk_env.Install(target="../..", source=['src/main/assets/ocflightserver_introspection.dat'])
+if jdk_env.get('SECURED') == '1':
+    jdk_env.Install(target="../..", source=['src/main/assets/ocflightserver_security.dat'])
+    jdk_env.Install(target="../..", source=['src/main/assets/ocflightserver_introspection.dat'])
diff --git a/java/examples-java/ocflightserver/run.sh b/java/examples-java/ocflightserver/run.sh
new file mode 100755 (executable)
index 0000000..8141a99
--- /dev/null
@@ -0,0 +1,7 @@
+# cd <iotivity>/out/linux/x86_64/release/java
+java -Djava.library.path=.. -jar ocflightserver.jar  "$1" "$2" "$3"
+
+# using the same 'name' will use the same uuid from names.prop file
+
+# java -Djava.library.path=.. -jar ocflightserver.jar  "name" "powerState" "dimmingSetting"
+# java -Djava.library.path=.. -jar ocflightserver.jar  Kitchen on 75
diff --git a/java/examples-java/ocflightserver/src/main/assets/PICS.json b/java/examples-java/ocflightserver/src/main/assets/PICS.json
new file mode 100644 (file)
index 0000000..2781f38
--- /dev/null
@@ -0,0 +1,32 @@
+{\r
+    "device": "ocf-light-server-java-test1",\r
+    "company": "Open Connectivity Foundation",\r
+    "role": "Server",\r
+    "supportedVerticalProfile": [\r
+        "Smart Home"\r
+    ],\r
+    "supportedDeviceTypes": [\r
+        "oic.d.light"\r
+    ],\r
+    "icv": "ocf.1.0.0",\r
+    "dmv": "ocf.res.1.3.0, ocf.sh.1.3.0",\r
+    "resources": [\r
+        "oic.r.switch.binary",\r
+        "oic.r.light.dimming",\r
+        "oic.r.csr",\r
+        "oic.r.crl",\r
+        "oic.r.roles",\r
+        "oic.r.sp"\r
+    ],\r
+    "jurisdictionSwitch": false,\r
+    "OTM": [\r
+        "oic.sec.doxm.jw"\r
+    ],\r
+    "contentFormatVersion": [ "1.0.0" ],\r
+    "acceptVersion": [ "1.0.0" ],\r
+\r
+    "multiValueQuerySupport": false,\r
+    "observableOICRES": false,\r
+    "persistentDeviceuuid": false,\r
+    "sct": 1\r
+}
\ No newline at end of file
diff --git a/java/examples-java/ocflightserver/src/main/assets/ocflightserver_introspection.dat b/java/examples-java/ocflightserver/src/main/assets/ocflightserver_introspection.dat
new file mode 100644 (file)
index 0000000..aacbac4
Binary files /dev/null and b/java/examples-java/ocflightserver/src/main/assets/ocflightserver_introspection.dat differ
diff --git a/java/examples-java/ocflightserver/src/main/assets/ocflightserver_introspection.json b/java/examples-java/ocflightserver/src/main/assets/ocflightserver_introspection.json
new file mode 100644 (file)
index 0000000..8268887
--- /dev/null
@@ -0,0 +1,371 @@
+{
+    "produces":[
+        "application/json"
+    ],
+    "parameters":{
+        "interface20":{
+            "enum":[
+                "oic.if.baseline",
+                "oic.if.r"
+            ],
+            "in":"query",
+            "type":"string",
+            "name":"if"
+        },
+        "interface":{
+            "enum":[
+                "oic.if.baseline",
+                "oic.if.a"
+            ],
+            "in":"query",
+            "type":"string",
+            "name":"if"
+        }
+    },
+    "swagger":"2.0",
+    "consumes":[
+        "application/json"
+    ],
+    "definitions":{
+        "Dimming":{
+            "required":[
+                "dimmingSetting"
+            ],
+            "type":"object",
+            "properties":{
+                "n":{
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":64
+                },
+                "if":{
+                    "readOnly":true,
+                    "type":"array",
+                    "items":{
+                        "enum":[
+                            "oic.if.baseline",
+                            "oic.if.a"
+                        ],
+                        "type":"string"
+                    },
+                    "description":"",
+                    "minItems":1
+                },
+                "rt":{
+                    "default":[
+                        "oic.r.light.dimming"
+                    ],
+                    "readOnly":true,
+                    "type":"array",
+                    "items":{
+                        "type":"string",
+                        "maxLength":64
+                    },
+                    "description":"",
+                    "minItems":1
+                },
+                "dimmingSetting":{
+                    "type":"integer",
+                    "description":""
+                }
+            }
+        },
+        "BinarySwitch":{
+            "required":[
+                "value"
+            ],
+            "type":"object",
+            "properties":{
+                "rt":{
+                    "default":[
+                        "oic.r.switch.binary"
+                    ],
+                    "readOnly":true,
+                    "type":"array",
+                    "items":{
+                        "type":"string",
+                        "maxLength":64
+                    },
+                    "description":"",
+                    "minItems":1
+                },
+                "n":{
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":64
+                },
+                "if":{
+                    "readOnly":true,
+                    "type":"array",
+                    "items":{
+                        "enum":[
+                            "oic.if.baseline",
+                            "oic.if.a"
+                        ],
+                        "type":"string"
+                    },
+                    "description":"",
+                    "minItems":1
+                },
+                "value":{
+                    "type":"boolean",
+                    "description":""
+                }
+            }
+        },
+        "Platform":{
+            "required":[
+                "pi",
+                "mnmn"
+            ],
+            "type":"object",
+            "properties":{
+                "mnos":{
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":64
+                },
+                "mnmn":{
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":64
+                },
+                "mnpv":{
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":64
+                },
+                "st":{
+                    "format":"date-time",
+                    "type":"string",
+                    "readOnly":true,
+                    "description":""
+                },
+                "pi":{
+                    "allOf":[
+                        {
+                            "pattern":"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$",
+                            "type":"string",
+                            "description":""
+                        },
+                        {
+                            "readOnly":true,
+                            "description":""
+                        }
+                    ]
+                },
+                "id":{
+                    "anyOf":[
+                        {
+                            "type":"string",
+                            "maxLength":64
+                        },
+                        {
+                            "pattern":"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$",
+                            "type":"string",
+                            "description":""
+                        }
+                    ],
+                    "readOnly":true,
+                    "description":""
+                },
+                "mnhw":{
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":64
+                },
+                "rt":{
+                    "default":[
+                        "oic.wk.p"
+                    ],
+                    "readOnly":true,
+                    "type":"array",
+                    "items":{
+                        "type":"string",
+                        "maxLength":64
+                    },
+                    "description":"",
+                    "minItems":1
+                },
+                "if":{
+                    "readOnly":true,
+                    "type":"array",
+                    "items":{
+                        "enum":[
+                            "oic.if.baseline",
+                            "oic.if.r"
+                        ],
+                        "type":"string"
+                    },
+                    "description":"",
+                    "minItems":1
+                },
+                "mnmo":{
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":64
+                },
+                "mnml":{
+                    "format":"uri",
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":256
+                },
+                "mnsl":{
+                    "format":"uri",
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":256
+                },
+                "mnfv":{
+                    "type":"string",
+                    "readOnly":true,
+                    "description":"",
+                    "maxLength":64
+                },
+                "mndt":{
+                    "allOf":[
+                        {
+                            "pattern":"^([0-9]{4})-(1[0-2]|0[1-9])-(3[0-1]|2[0-9]|1[0-9]|0[1-9])$",
+                            "type":"string",
+                            "description":""
+                        },
+                        {
+                            "readOnly":true,
+                            "description":""
+                        }
+                    ]
+                }
+            }
+        }
+    },
+    "info":{
+        "license":{
+            "name":"copyright 2016-2017 Open Connectivity Foundation, Inc. All rights reserved."
+        },
+        "version":"v1.1.0-20160519",
+        "title":"Binary Switch"
+    },
+    "paths":{
+        "/oic/p":{
+            "get":{
+                "responses":{
+                    "200":{
+                        "schema":{
+                            "$ref":"#/definitions/Platform"
+                        },
+                        "description":""
+                    }
+                },
+                "parameters":[
+                    {
+                        "$ref":"#/parameters/interface20"
+                    }
+                ],
+                "description":""
+            }
+        },
+        "/ocf/switch":{
+            "post":{
+                "responses":{
+                    "200":{
+                        "schema":{
+                            "$ref":"#/definitions/BinarySwitch"
+                        },
+                        "description":""
+                    }
+                },
+                "parameters":[
+                    {
+                        "$ref":"#/parameters/interface"
+                    },
+                    {
+                        "required":true,
+                        "in":"body",
+                        "schema":{
+                            "$ref":"#/definitions/BinarySwitch"
+                        },
+                        "name":"body"
+                    }
+                ],
+                "description":""
+            },
+            "get":{
+                "responses":{
+                    "200":{
+                        "schema":{
+                            "$ref":"#/definitions/BinarySwitch"
+                        },
+                        "description":""
+                    }
+                },
+                "parameters":[
+                    {
+                        "$ref":"#/parameters/interface"
+                    }
+                ],
+                "description":""
+            }
+        },
+        "/ocf/dimming":{
+            "post":{
+                "responses":{
+                    "200":{
+                        "schema":{
+                            "$ref":"#/definitions/Dimming"
+                        },
+                        "description":""
+                    },
+                    "403":{
+                        "schema":{
+                            "$ref":"#/definitions/Dimming"
+                        },
+                        "description":""
+                    }
+                },
+                "parameters":[
+                    {
+                        "$ref":"#/parameters/interface"
+                    },
+                    {
+                        "required":true,
+                        "in":"body",
+                        "schema":{
+                            "$ref":"#/definitions/Dimming"
+                        },
+                        "name":"body"
+                    }
+                ],
+                "description":""
+            },
+            "get":{
+                "responses":{
+                    "200":{
+                        "schema":{
+                            "$ref":"#/definitions/Dimming"
+                        },
+                        "description":""
+                    }
+                },
+                "parameters":[
+                    {
+                        "$ref":"#/parameters/interface"
+                    }
+                ],
+                "description":""
+            }
+        }
+    },
+    "schemes":[
+        "http"
+    ]
+}
\ No newline at end of file
diff --git a/java/examples-java/ocflightserver/src/main/assets/ocflightserver_security.dat b/java/examples-java/ocflightserver/src/main/assets/ocflightserver_security.dat
new file mode 100644 (file)
index 0000000..3cf8bdb
Binary files /dev/null and b/java/examples-java/ocflightserver/src/main/assets/ocflightserver_security.dat differ
diff --git a/java/examples-java/ocflightserver/src/main/assets/ocflightserver_security.json b/java/examples-java/ocflightserver/src/main/assets/ocflightserver_security.json
new file mode 100644 (file)
index 0000000..3928c60
--- /dev/null
@@ -0,0 +1,64 @@
+{
+    "acl": {
+        "aclist2": [
+            {
+                "aceid": 1,
+                "subject": { "conntype": "anon-clear" },
+                "resources": [
+                    { "href": "/oic/res" },
+                    { "href": "/oic/d" },
+                    { "href": "/oic/p" },
+                    { "wc": "-" }
+                ],
+                "permission": 2
+            },
+            {
+                "aceid": 2,
+                "subject": { "conntype": "auth-crypt" },
+                "resources": [
+                    { "href": "/oic/res" },
+                    { "href": "/oic/d" },
+                    { "href": "/oic/p" },
+                    { "wc": "+" }
+                ],
+                "permission": 2
+            },
+            {
+                "aceid": 3,
+                "subject": { "conntype": "anon-clear" },
+                "resources": [
+                    { "href": "/oic/sec/doxm" }
+                ],
+                "permission": 14
+            },
+            {
+                "aceid": 4,
+                "subject": { "conntype": "auth-crypt" },
+                "resources": [
+                    { "href": "/oic/sec/doxm" },
+                    { "href": "/oic/sec/roles" }
+                ],
+                "permission": 14
+            }
+        ],
+        "rowneruuid": "00000000-0000-0000-0000-000000000000"
+    },
+    "pstat": {
+        "dos": { "s": 1, "p": false },
+        "isop": false,
+        "cm": 2,
+        "tm": 0,
+        "om": 4,
+        "sm": 4,
+        "rowneruuid": "00000000-0000-0000-0000-000000000000"
+    },
+    "doxm": {
+        "oxms": [0],
+        "oxmsel": 0,
+        "sct": 1,
+        "owned": false,
+        "deviceuuid": "12345678-1234-1234-1234-123456789012",
+        "devowneruuid": "00000000-0000-0000-0000-000000000000",
+        "rowneruuid": "00000000-0000-0000-0000-000000000000"
+    }
+}
diff --git a/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Dimming.java b/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Dimming.java
new file mode 100644 (file)
index 0000000..6298de7
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2018 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;
+
+/**
+ * Dimming
+ *
+ * This class represents a dimming resource
+ */
+public class Dimming extends Resource implements LightControlDimmingObserver {
+    static public final String RESOURCE_TYPE = "oic.r.light.dimming";
+    static public final String RESOURCE_INTERFACE = "oic.if.a";
+
+    static public final String DIMMING_SETTING_KEY = "dimmingSetting";
+
+    private int dimmingValue;
+
+    public Dimming(String uuid) {
+        super("/ocf/dimming", RESOURCE_TYPE, RESOURCE_INTERFACE);
+    }
+
+    public void setOcRepresentation(OcRepresentation rep) {
+        try {
+            if (rep.hasAttribute(DIMMING_SETTING_KEY)) {
+                dimmingValue = rep.getValue(DIMMING_SETTING_KEY);
+                dimmingValue = Math.max(0, dimmingValue);
+                dimmingValue = Math.min(100, dimmingValue);
+            }
+        } catch (OcException e) {
+            OcfLightServer.msgError(e.toString());
+            OcfLightServer.msgError("Failed to get representation values");
+        }
+    }
+
+    public OcRepresentation getOcRepresentation() {
+        OcRepresentation rep = new OcRepresentation();
+        try {
+            dimmingValue = Math.max(0, dimmingValue);
+            dimmingValue = Math.min(100, dimmingValue);
+            rep.setValue(DIMMING_SETTING_KEY, dimmingValue);
+            rep.setValue(RT_KEY, this.getResourceTypeArray());
+            rep.setValue(IF_KEY, this.getResourceInterfaceArray());
+        } catch (OcException e) {
+            OcfLightServer.msgError(e.toString());
+            OcfLightServer.msgError("Failed to set representation values");
+        }
+        return rep;
+    }
+
+    public int getDimmingValue() {
+        return dimmingValue;
+    }
+
+    public void setDimmingValue(int dimmingValue) {
+        dimmingValue = Math.max(0, dimmingValue);
+        dimmingValue = Math.min(100, dimmingValue);
+        this.dimmingValue = dimmingValue;
+    }
+
+    @Override
+    public void update(int dimmingValue) {
+        setDimmingValue(dimmingValue);
+        notifyObservers(null);
+    }
+
+    @Override
+    public String toString() {
+        return "[" + super.toString() + ", " + DIMMING_SETTING_KEY + ": " + dimmingValue + "]";
+    }
+}
diff --git a/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Light.java b/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Light.java
new file mode 100644 (file)
index 0000000..3d62899
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2018 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;
+
+/**
+ * Light
+ *
+ * This class represents a light resource
+ */
+public class Light {
+    static public final String RESOURCE_TYPE = "oic.d.light";
+    static public final String DEVICE_RESOURCE_TYPE = "oic.wk.d";
+
+    private Switch switchRes;
+    private Dimming dimmingRes;
+
+    private String deviceName;
+
+    public Light(String name, String uuid, boolean powerOn, int dimmingValue, LightControlPanel ui) {
+        deviceName = name;
+
+        switchRes = new Switch(uuid);
+        switchRes.setValue(powerOn);
+        switchRes.addObserver(ui);
+        ui.addObserver(switchRes);
+        OcfLightServer.msg("Created switch resource: " + switchRes);
+
+        dimmingRes = new Dimming(uuid);
+        dimmingRes.setDimmingValue(dimmingValue);
+        dimmingRes.addObserver(ui);
+        ui.addObserver(dimmingRes);
+        OcfLightServer.msg("Created dimming resource: " + dimmingRes);
+
+        OcfLightServer.msg("Created light resource: " + this);
+    }
+
+    public void unregister() {
+        try {
+            switchRes.unregisterResource();
+        } catch (OcException e) {
+            OcfLightServer.msgError("Failed to unregister " + switchRes.getResourceUri());
+            e.printStackTrace();
+        }
+        try {
+            dimmingRes.unregisterResource();
+        } catch (OcException e) {
+            OcfLightServer.msgError("Failed to unregister " + dimmingRes.getResourceUri());
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "[" + deviceName + ", "
+                   + Switch.VALUE_KEY + ": " + switchRes.getValue() + ", "
+                   + Dimming.DIMMING_SETTING_KEY + ": " + dimmingRes.getDimmingValue() + "]";
+    }
+}
diff --git a/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/LightControlDimmingObserver.java b/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/LightControlDimmingObserver.java
new file mode 100644 (file)
index 0000000..067ac34
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2018 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;
+
+/**
+ * LightControlDimmingObserver
+ */
+public interface LightControlDimmingObserver {
+
+    void update(int dimmingValue);
+}
diff --git a/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/LightControlPanel.java b/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/LightControlPanel.java
new file mode 100644 (file)
index 0000000..71251ae
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2018 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.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.util.Map;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSeparator;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * Light Control Panel
+ */
+public class LightControlPanel extends JPanel implements Observer {
+
+    private JCheckBox powerCheckBox;
+    private SpinnerNumberModel dimmingValueModel;
+
+    private JCheckBox slowResponseCheckBox;
+
+    public LightControlPanel(boolean powerOn, int dimmingValue) {
+        setLayout(new GridBagLayout());
+
+        JLabel switchLabel = new JLabel("Binary Switch: ");
+        powerCheckBox = new JCheckBox(powerOn ? "On" : "Off", powerOn);
+        powerCheckBox.addChangeListener(new ChangeListener() {
+            @Override
+            public void stateChanged(ChangeEvent changeEvent) {
+                powerCheckBox.setText(powerCheckBox.isSelected() ? "On" : "Off");
+            }
+        });
+        powerCheckBox.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                notifySwitchObservers();
+            }
+        });
+        add(switchLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4,4,4,4), 0, 0));
+        add(powerCheckBox, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4,4,4,4), 0, 0));
+
+        JLabel dimmingLabel = new JLabel("Dimming Setting: ");
+        dimmingValueModel = new SpinnerNumberModel(dimmingValue, 0, 100, 1);
+        JSpinner dimmingValueSpinner = new JSpinner(dimmingValueModel);
+        // only allow keypad arrows or mouse clicks
+        ((JSpinner.DefaultEditor) dimmingValueSpinner.getEditor()).getTextField().setEditable(false);
+        ((JSpinner.DefaultEditor) dimmingValueSpinner.getEditor()).getTextField().addKeyListener(new KeyListener() {
+            @Override
+            public void keyTyped(KeyEvent e) {
+            }
+            @Override
+            public void keyPressed(KeyEvent e) {
+            }
+            @Override
+            public void keyReleased(KeyEvent e) {
+                int code = e.getKeyCode();
+                if ((code == KeyEvent.VK_UP) || (code == KeyEvent.VK_KP_UP) || (code == KeyEvent.VK_DOWN) || (code == KeyEvent.VK_KP_DOWN)) {
+                    notifyDimmingObservers();
+                }
+            }
+        });
+        Component[] components = dimmingValueSpinner.getComponents();
+        for (Component component : components) {
+            if (component instanceof JButton) {
+                ((JButton)component).addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        notifyDimmingObservers();
+                    }
+                });
+            }
+        }
+        add(dimmingLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4,4,4,4), 0, 0));
+        add(dimmingValueSpinner, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4,4,4,4), 0, 0));
+
+        add(new JSeparator(), new GridBagConstraints(0, 2, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(6,4,4,4), 0, 0));
+
+        slowResponseCheckBox = new JCheckBox("Send Slow (Asynchronous) Responses");
+        add(slowResponseCheckBox, new GridBagConstraints(0, 3, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4,4,4,4), 0, 0));
+
+        add(new JPanel(), new GridBagConstraints(0, 4, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0,0,0,0), 0, 0));
+    }
+
+    public boolean useSlowResponse() {
+        return slowResponseCheckBox.isSelected();
+    }
+
+    private void setPowerOn(boolean powerOn) {
+        powerCheckBox.setSelected(powerOn);
+    }
+
+    private void setDimmingValue(int dimmingValue) {
+        dimmingValueModel.setValue(dimmingValue);
+    }
+
+    @Override
+    public void update(Observable o, Object arg) {
+        boolean repaintRequired = false;
+        if (o instanceof Switch) {
+            boolean powerOn = ((Switch) o).getValue();
+            setPowerOn(powerOn);
+            repaintRequired = true;
+
+        } else if (o instanceof Dimming) {
+            int dimmingValue = ((Dimming) o).getDimmingValue();
+            setDimmingValue(dimmingValue);
+            repaintRequired = true;
+
+        } else {
+            // ignore
+        }
+
+        if (repaintRequired) {
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    repaint();
+                }
+            });
+        }
+    }
+
+    // LightControlObservable implementation
+    private Map<Integer, LightControlSwitchObserver> switchObservers = new ConcurrentHashMap<Integer, LightControlSwitchObserver>();
+    private Map<Integer, LightControlDimmingObserver> dimmingObservers = new ConcurrentHashMap<Integer, LightControlDimmingObserver>();
+
+    public void addObserver(LightControlSwitchObserver observer) {
+        switchObservers.put(observer.hashCode(), observer);
+    }
+
+    public void addObserver(LightControlDimmingObserver observer) {
+        dimmingObservers.put(observer.hashCode(), observer);
+    }
+
+    private void notifySwitchObservers() {
+        Thread observerNotifier = new Thread(new Runnable() {
+            public void run() {
+                for (LightControlSwitchObserver observer : switchObservers.values()) {
+                    observer.update(powerCheckBox.isSelected());
+                }
+            }
+        });
+        observerNotifier.setDaemon(true);
+        observerNotifier.start();
+    }
+
+    private void notifyDimmingObservers() {
+        Thread observerNotifier = new Thread(new Runnable() {
+            public void run() {
+                for (LightControlDimmingObserver observer : dimmingObservers.values()) {
+                    observer.update(dimmingValueModel.getNumber().intValue());
+                }
+            }
+        });
+        observerNotifier.setDaemon(true);
+        observerNotifier.start();
+    }
+}
diff --git a/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/LightControlSwitchObserver.java b/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/LightControlSwitchObserver.java
new file mode 100644 (file)
index 0000000..3fd2bb6
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2018 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;
+
+/**
+ * LightControlSwitchObserver
+ */
+public interface LightControlSwitchObserver {
+
+    void update(boolean powerOn);
+}
diff --git a/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java b/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/NamesPropertyFile.java
new file mode 100644 (file)
index 0000000..65f4d12
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2018 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) {
+            OcfLightServer.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) {
+            OcfLightServer.msgError("Error loading name properties: " + e.toString());
+            e.printStackTrace();
+
+        } finally {
+            if (inStream != null) {
+                try {
+                    inStream.close();
+                } catch (IOException e) {
+                    OcfLightServer.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) {
+            OcfLightServer.msgError("Error storing name properties: " + e.toString());
+            e.printStackTrace();
+        }
+
+        finally {
+            if (outStream != null) {
+                try {
+                    outStream.close();
+                } catch (IOException e) {
+                    OcfLightServer.msgError("Error closing name properties file: " + e.toString());
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+}
diff --git a/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/OcfLightServer.java b/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/OcfLightServer.java
new file mode 100644 (file)
index 0000000..30b290d
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2018 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.OcException;
+import org.iotivity.base.OcPlatform;
+import org.iotivity.base.OcPlatformInfo;
+import org.iotivity.base.OcResourceHandle;
+import org.iotivity.base.PayloadType;
+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.File;
+import java.net.URISyntaxException;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.UUID;
+
+import javax.swing.JFrame;
+import javax.swing.WindowConstants;
+
+/**
+ * OcfLightServer
+ */
+public class OcfLightServer {
+
+    static Light light;
+    static String name;
+    static boolean powerOn = true;
+    static int dimmingValue = 100;
+
+    static LightControlPanel lightControlPanel;
+
+    public static void main(String args[]) throws IOException, InterruptedException {
+
+        parseNameAndInitialSettings(args);
+
+        File jarFile = null;
+        try {
+            jarFile = new File(OcfLightServer.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
+
+        } catch (URISyntaxException e) {
+            OcfLightServer.msgError("Failed to find jar file path.");
+            e.printStackTrace();
+            System.exit(-1);
+        }
+
+        String jarFilePath = jarFile.getParent();
+        jarFilePath = (jarFilePath != null) ? jarFilePath : "";
+
+        File securityFile = new File(jarFilePath+"/ocflightserver_security.dat");
+        if (! (securityFile.exists() && securityFile.isFile())) {
+            OcfLightServer.msgError("Security file " + securityFile.getAbsolutePath() + " not found");
+            System.exit(-1);
+        }
+
+        File introspectionFile = new File(jarFilePath+"/ocflightserver_introspection.dat");
+        if (! (introspectionFile.exists() && introspectionFile.isFile())) {
+            OcfLightServer.msgError("Introspection file " + introspectionFile.getAbsolutePath() + " not found");
+            System.exit(-1);
+        }
+
+        PlatformConfig platformConfig = new PlatformConfig(ServiceType.IN_PROC, ModeType.SERVER, "0.0.0.0", 0,
+                QualityOfService.LOW, securityFile.getAbsolutePath(), introspectionFile.getAbsolutePath());
+
+        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);
+        }
+
+        TimeZone timeZone = TimeZone.getTimeZone("UTC");
+        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+        dateFormat.setTimeZone(timeZone);
+        String nowAsIso8601 = dateFormat.format(new Date());
+
+        OcPlatformInfo platformInfo = new OcPlatformInfo(
+                uuid,
+                "manufacturerName",
+                "http://www.manufacturer.com",
+                "modelNumber",
+                "2018-03-15",
+                "1.0",
+                "1.0",
+                "1.0",
+                "1.0",
+                "http://www.support.com",
+                nowAsIso8601
+        );
+
+        try {
+            msg("Registering platform info");
+            OcPlatform.registerPlatformInfo(platformInfo);
+
+        } catch (OcException e) {
+            OcfLightServer.msgError("Failed to register platform info.");
+            e.printStackTrace();
+        }
+
+        try {
+            OcPlatform.setPropertyValue(PayloadType.DEVICE.getValue(), "n", name);
+            OcPlatform.setPropertyValue(PayloadType.DEVICE.getValue(), "piid", uuid);
+            OcPlatform.setPropertyValue(PayloadType.DEVICE.getValue(), "icv", "ocf.1.0.0");
+            OcPlatform.setPropertyValue(PayloadType.DEVICE.getValue(), "dmv", "ocf.res.1.3.0,ocf.sh.1.3.0");
+
+        } catch (OcException e) {
+            OcfLightServer.msgError("Failed to create device properties");
+            e.printStackTrace();
+        }
+
+        try {
+            OcResourceHandle deviceResourceHandle = OcPlatform.getResourceHandleAtUri(OcPlatform.WELL_KNOWN_DEVICE_QUERY);
+            if (deviceResourceHandle != null) {
+                OcPlatform.bindTypeToResource(deviceResourceHandle, Light.RESOURCE_TYPE);
+            }
+
+        } catch (OcException e) {
+            OcfLightServer.msgError("Failed to bind device type to /oic/d resource");
+            e.printStackTrace();
+        }
+
+        JFrame frame = new JFrame(name);
+        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+
+        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(true);
+        frame.setLayout(new FlowLayout());
+
+        lightControlPanel = new LightControlPanel(powerOn, dimmingValue);
+        light = new Light(name, uuid, powerOn, dimmingValue, lightControlPanel);
+
+        frame.setContentPane(lightControlPanel);
+        frame.pack();
+        frame.setVisible(true);
+    }
+
+    private static void parseNameAndInitialSettings(String args[]) {
+        if (args.length > 0) {
+            name = args[0];
+        }
+
+        if (args.length > 1) {
+            String arg = args[1];
+            if (!arg.isEmpty()) {
+                powerOn = arg.equalsIgnoreCase("true") || arg.equalsIgnoreCase("on") || arg.equalsIgnoreCase("yes")
+                        || arg.equals("1");
+            }
+        }
+
+        if (args.length > 2) {
+            try {
+                dimmingValue = Integer.valueOf(args[2]);
+            } catch (NumberFormatException e) {
+                msg("Dimming setting must be an integer in the range (0, 100), using default 100.");
+            }
+
+            dimmingValue = Math.max(0, dimmingValue);
+            dimmingValue = Math.min(100, dimmingValue);
+        }
+
+        if (name == null || name.isEmpty()) {
+            name = "Light " + (System.currentTimeMillis() % 10000);
+        }
+    }
+
+    public static boolean useSlowResponse() {
+        return lightControlPanel.useSlowResponse();
+    }
+
+    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);
+    }
+}
diff --git a/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Resource.java b/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Resource.java
new file mode 100644 (file)
index 0000000..df64a27
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2018 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.ArrayList;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Observable;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Resource
+ *
+ * This is the base class for all resources
+ */
+
+abstract public class Resource extends Observable implements OcPlatform.EntityHandler {
+    static public final String RT_KEY = "rt";
+    static public final String IF_KEY = "if";
+
+    private String resUri;
+    private String resType;
+    private String resIf;
+    private OcResourceHandle resHandle;
+    private Map<Byte,Byte> observerIds = new ConcurrentHashMap<Byte,Byte>();
+
+    public Resource(String uri, String resType, String resIf) {
+        resUri = uri;
+        this.resType = resType;
+        this.resIf = resIf;
+
+        try {
+            resHandle = OcPlatform.registerResource(resUri, resType, resIf, this,
+                    EnumSet.of(ResourceProperty.DISCOVERABLE, ResourceProperty.OBSERVABLE, ResourceProperty.SECURE, ResourceProperty.SLOW));
+            if (resHandle != null) {
+                OcPlatform.bindInterfaceToResource(resHandle, OcPlatform.DEFAULT_INTERFACE);
+            }
+
+        } catch (OcException e) {
+            OcfLightServer.msgError("Failed to create resource " + resUri);
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public synchronized EntityHandlerResult handleEntity(final OcResourceRequest request) {
+        EntityHandlerResult ehResult = EntityHandlerResult.ERROR;
+        if (null == request) {
+            OcfLightServer.msg("Server request is invalid");
+            return ehResult;
+        }
+        // Get the request flags
+        EnumSet<RequestHandlerFlag> requestFlags = request.getRequestHandlerFlagSet();
+        if (requestFlags.contains(RequestHandlerFlag.INIT)) {
+            OcfLightServer.msg("Request Flag: Init for " + request.getResourceUri());
+            ehResult = EntityHandlerResult.OK;
+        }
+        if (requestFlags.contains(RequestHandlerFlag.REQUEST)) {
+            ehResult = handleRequest(request);
+        }
+        if (requestFlags.contains(RequestHandlerFlag.OBSERVER)) {
+            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()) {
+            for (Map.Entry<String, String> entry : queries.entrySet()) {
+                OcfLightServer.msg("Query key: " + entry.getKey() + " value: " + entry.getValue());
+            }
+        }
+
+        // Get the request type
+        RequestType requestType = request.getRequestType();
+        switch (requestType) {
+        case GET:
+            ehResult = handleGetRequest(request);
+            break;
+        case PUT:
+            ehResult = handlePutRequest(request);
+            break;
+        case POST:
+            ehResult = handlePutRequest(request); // same as put
+            break;
+        case DELETE:
+            ehResult = handleDeleteRequest();
+            break;
+        }
+        return ehResult;
+    }
+
+    private EntityHandlerResult handleGetRequest(final OcResourceRequest request) {
+        if (OcfLightServer.useSlowResponse()) {
+            Random random = new Random();
+            int delay = random.nextInt(10) + 1; // random int between 1 and 10 inclusive
+            OcfLightServer.msg("Sending slow get response in " + delay + " seconds");
+
+            ScheduledExecutorService slowResponseExecutor = new ScheduledThreadPoolExecutor(1);
+            slowResponseExecutor.schedule(new Runnable() {
+                public void run() {
+                  OcResourceResponse response = new OcResourceResponse();
+                  response.setRequestHandle(request.getRequestHandle());
+                  response.setResourceHandle(request.getResourceHandle());
+                  response.setResponseResult(EntityHandlerResult.OK);
+                  response.setResourceRepresentation(getOcRepresentation());
+                  sendResponse(response);
+                }
+            }, delay, TimeUnit.SECONDS);
+
+            return EntityHandlerResult.SLOW;
+        }
+
+        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) {
+        if (OcfLightServer.useSlowResponse()) {
+            Random random = new Random();
+            int delay = random.nextInt(10) + 1; // random int between 1 and 10 inclusive
+            OcfLightServer.msg("Sending slow put response in " + delay + " seconds");
+
+            ScheduledExecutorService slowResponseExecutor = new ScheduledThreadPoolExecutor(1);
+            slowResponseExecutor.schedule(new Runnable() {
+                public void run() {
+                    OcResourceResponse response = new OcResourceResponse();
+                    response.setRequestHandle(request.getRequestHandle());
+                    response.setResourceHandle(request.getResourceHandle());
+
+                    setOcRepresentation(request.getResourceRepresentation());
+                    response.setResourceRepresentation(getOcRepresentation());
+                    response.setResponseResult(EntityHandlerResult.OK);
+                    sendResponse(response);
+
+                    // notify ocf observers
+                    notifyObservers(request);
+
+                    // notify ui observers (ie implementors of Observer)
+                    setChanged();
+                    notifyObservers();
+                }
+            }, delay, TimeUnit.SECONDS);
+
+            return EntityHandlerResult.SLOW;
+        }
+
+        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
+        ScheduledExecutorService observerNotifierExecutor = new ScheduledThreadPoolExecutor(1);
+        observerNotifierExecutor.schedule(new Runnable() {
+            public void run() {
+                // notify ocf observers
+                notifyObservers(request);
+
+                // notify ui observers (ie implementors of Observer)
+                setChanged();
+                notifyObservers();
+            }
+        }, 200, TimeUnit.MILLISECONDS);
+
+        return sendResponse(response);
+    }
+
+    private EntityHandlerResult handleDeleteRequest() {
+        try {
+            unregisterResource();
+            return EntityHandlerResult.RESOURCE_DELETED;
+        } catch (OcException e) {
+            OcfLightServer.msgError(e.toString());
+            OcfLightServer.msgError("Failed to unregister resource " + resUri);
+            return EntityHandlerResult.ERROR;
+        }
+    }
+
+    private EntityHandlerResult handleObserver(final OcResourceRequest request) {
+        ObservationInfo observationInfo = request.getObservationInfo();
+        switch (observationInfo.getObserveAction()) {
+        case REGISTER:
+            byte id = observationInfo.getOcObservationId();
+            OcfLightServer.msg("handleObserver register observer " + String.format("%02x", id));
+            observerIds.put(id, id);
+            break;
+        case UNREGISTER:
+            OcfLightServer.msg("handleObserver unregister observer " + String.format("%02x", observationInfo.getOcObservationId()));
+            observerIds.remove(observationInfo.getOcObservationId());
+            break;
+        }
+        return OcfLightServer.useSlowResponse() ? EntityHandlerResult.SLOW : EntityHandlerResult.OK;
+    }
+
+    protected void notifyObservers(OcResourceRequest request) {
+        if (!observerIds.isEmpty()) {
+            try {
+                OcResourceResponse response = new OcResourceResponse();
+                response.setResourceRepresentation(getOcRepresentation());
+                for (Byte id : observerIds.keySet()) {
+                    OcfLightServer.msg("Notifying observer " + String.format("%02x", id) + " for resource " + this);
+                }
+                OcPlatform.notifyListOfObservers(getResourceHandle(), new ArrayList<Byte>(observerIds.keySet()), response);
+            } catch (OcException e) {
+                ErrorCode errorCode = e.getErrorCode();
+                if (ErrorCode.NO_OBSERVERS == errorCode) {
+                    OcfLightServer.msg("No observers found");
+                } else {
+                    OcfLightServer.msgError(e.toString());
+                    OcfLightServer.msgError("Failed to notify observers");
+                }
+            }
+        }
+    }
+
+    private EntityHandlerResult sendResponse(OcResourceResponse response) {
+        try {
+            OcPlatform.sendResponse(response);
+            return EntityHandlerResult.OK;
+        } catch (OcException e) {
+            OcfLightServer.msgError(e.toString());
+            OcfLightServer.msgError("Failed to send response");
+            return EntityHandlerResult.ERROR;
+        }
+    }
+
+    public synchronized void unregisterResource() throws OcException {
+        if (null != resHandle) {
+            OcPlatform.unregisterResource(resHandle);
+            OcfLightServer.msg("Unregistered resource " + resUri);
+        }
+    }
+
+    public abstract void setOcRepresentation(OcRepresentation rep);
+
+    public abstract OcRepresentation getOcRepresentation();
+
+    public String getResourceUri() {
+        return resUri;
+    }
+
+    public OcResourceHandle getResourceHandle() {
+        return resHandle;
+    }
+
+    public String[] getResourceTypeArray() {
+        String[] rtArray = new String[1];
+        rtArray[0] = resType;
+        return rtArray;
+    }
+
+    public String[] getResourceInterfaceArray() {
+        String[] ifArray = new String[2];
+        ifArray[0] = OcPlatform.DEFAULT_INTERFACE;
+        ifArray[1] = resIf;
+        return ifArray;
+    }
+
+    @Override
+    public String toString() {
+        return resUri;
+    }
+}
diff --git a/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Switch.java b/java/examples-java/ocflightserver/src/main/java/org/iotivity/base/examples/Switch.java
new file mode 100644 (file)
index 0000000..02182d1
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *******************************************************************
+ *
+ * Copyright 2018 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;
+
+/**
+ * Switch
+ *
+ * This class represents a binary switch resource
+ */
+public class Switch extends Resource implements LightControlSwitchObserver {
+    static public final String RESOURCE_TYPE = "oic.r.switch.binary";
+    static public final String RESOURCE_INTERFACE = "oic.if.a";
+
+    static public final String VALUE_KEY = "value";
+
+    private boolean powerOn;
+
+    public Switch(String uuid) {
+        super("/ocf/switch", RESOURCE_TYPE, RESOURCE_INTERFACE);
+    }
+
+    public void setOcRepresentation(OcRepresentation rep) {
+        try {
+            if (rep.hasAttribute(VALUE_KEY)) {
+                powerOn = rep.getValue(VALUE_KEY);
+            }
+        } catch (OcException e) {
+            OcfLightServer.msgError(e.toString());
+            OcfLightServer.msgError("Failed to get representation values");
+        }
+    }
+
+    public OcRepresentation getOcRepresentation() {
+        OcRepresentation rep = new OcRepresentation();
+        try {
+            rep.setValue(VALUE_KEY, powerOn);
+            rep.setValue(RT_KEY, this.getResourceTypeArray());
+            rep.setValue(IF_KEY, this.getResourceInterfaceArray());
+        } catch (OcException e) {
+            OcfLightServer.msgError(e.toString());
+            OcfLightServer.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) {
+        setValue(powerOn);
+        notifyObservers(null);
+    }
+
+    @Override
+    public String toString() {
+        return "[" + super.toString() + ", " + VALUE_KEY + ": " + powerOn + "]";
+    }
+}