Fix PUT and Observe relay on cloud stack
authorJee Hyeok Kim <jihyeok13.kim@samsung.com>
Mon, 14 Mar 2016 08:40:16 +0000 (17:40 +0900)
committerJee Hyeok Kim <jihyeok13.kim@samsung.com>
Wed, 16 Mar 2016 22:41:40 +0000 (22:41 +0000)
1. Fix PUT and Observe relay
2. Add PUT and Observe scenario for native sample client
3. Add Testcases for cloud stack
4. Remove Net Utility for logging local IP address

Change-Id: I03c0bd9afc553e1705c67f24db0d4420405fdf1d
Signed-off-by: Jee Hyeok Kim <jihyeok13.kim@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/5847
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
14 files changed:
cloud/account/README
cloud/account/src/main/java/org/iotivity/cloud/accountserver/AccountServer.java
cloud/interface/README
cloud/interface/src/main/java/org/iotivity/cloud/ciserver/CloudInterfaceServer.java
cloud/interface/src/main/java/org/iotivity/cloud/ciserver/protocols/CoapRelayHandler.java
cloud/interface/src/test/java/org/iotivity/cloud/ciserver/testci/TestCloudInterface.java
cloud/resourcedirectory/README
cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/ResourceDirectoryServer.java
cloud/samples/client/SConscript
cloud/samples/client/sample_device.cpp
cloud/stack/src/main/java/org/iotivity/cloud/base/SessionManager.java
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapEncoder.java
cloud/stack/src/main/java/org/iotivity/cloud/util/Net.java [deleted file]
cloud/stack/src/test/java/org/iotivity/cloud/util/UtilTest.java [new file with mode: 0644]

index 4a2615b..08ac84c 100644 (file)
@@ -10,7 +10,7 @@ Build and Run
 2) Build a CloudStack. If you are building first time, then build the stack.
 
        go to "stack" folder in root directory
-       $ mvn install
+       $ mvn install -Dmaven.test.skip=true
 
 3) Build a .jar file
 
index 96c36bf..8b49953 100644 (file)
@@ -28,7 +28,6 @@ import org.iotivity.cloud.accountserver.resources.AuthResource;
 import org.iotivity.cloud.base.CoapServer;
 import org.iotivity.cloud.base.ResourceManager;
 import org.iotivity.cloud.util.Logger;
-import org.iotivity.cloud.util.Net;
 
 /**
  * 
@@ -40,11 +39,6 @@ public class AccountServer {
     public static void main(String[] args) throws Exception {
 
         System.out.println("-----Account SERVER-----");
-        String hostAddress = Net.getMyIpAddress();
-        if (hostAddress.equals("") == true) {
-            Logger.e("cannot find host address.");
-            return;
-        }
 
         if (args.length != 1) {
             Logger.e("coap server port required");
index 698c03f..0ff3f64 100644 (file)
@@ -9,7 +9,7 @@ Build and Run
 2) Build a CloudStack. If you are building first time, then build the stack.
 
        go to "stack" folder in root directory
-       $ mvn install
+       $ mvn install -Dmaven.test.skip=true
 
 3) Build a .jar file
 
index 88e0577..972830f 100644 (file)
@@ -31,18 +31,12 @@ import org.iotivity.cloud.ciserver.protocols.CoapRelayHandler;
 import org.iotivity.cloud.ciserver.resources.KeepAliveResource;
 import org.iotivity.cloud.util.CoapLogHandler;
 import org.iotivity.cloud.util.Logger;
-import org.iotivity.cloud.util.Net;
 
 public class CloudInterfaceServer {
 
     public static void main(String[] args) throws Exception {
 
         System.out.println("-----CI SERVER-------");
-        String hostAddress = Net.getMyIpAddress();
-        if (hostAddress.equals("") == true) {
-            Logger.e("cannot find host address.");
-            return;
-        }
 
         if (args.length != 5) {
             Logger.e(
@@ -66,7 +60,6 @@ public class CloudInterfaceServer {
 
         coapServer.addHandler(new CoapLogHandler());
 
-        // Comment the following one line to make CI server run alone
         coapServer.addHandler(new CoapRelayHandler(sessionManager, args[1],
                 Integer.parseInt(args[2]), args[3], Integer.parseInt(args[4])));
 
index 3629097..60cac3a 100644 (file)
@@ -24,7 +24,6 @@ package org.iotivity.cloud.ciserver.protocols;
 import java.net.InetSocketAddress;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 
 import org.iotivity.cloud.base.CoapClient;
@@ -34,7 +33,6 @@ import org.iotivity.cloud.base.protocols.coap.CoapResponse;
 import org.iotivity.cloud.base.protocols.coap.enums.CoapMethod;
 import org.iotivity.cloud.base.protocols.coap.enums.CoapStatus;
 import org.iotivity.cloud.ciserver.Constants;
-import org.iotivity.cloud.util.Cbor;
 import org.iotivity.cloud.util.Logger;
 
 import io.netty.channel.ChannelDuplexHandler;
@@ -155,8 +153,6 @@ public class CoapRelayHandler extends ChannelDuplexHandler {
     private static final AttributeKey<ChannelHandlerContext> keyDevice = AttributeKey
             .newInstance("deviceCtx");
 
-    private Cbor<HashMap<Object, Object>> cbor = new Cbor<HashMap<Object, Object>>();
-
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object msg)
             throws Exception {
@@ -285,15 +281,21 @@ public class CoapRelayHandler extends ChannelDuplexHandler {
             }
 
         } else if (msg instanceof CoapResponse) {
-            if (ctx.attr(keyDevice).get() != null) {
+            ChannelHandlerContext resourceClient = ctx.attr(keyDevice).get();
+            if (resourceClient != null) {
                 Logger.i("Forwards message to client");
 
-                if (((CoapResponse) msg).getPayload() == null)
-                    Logger.i("No payload in reponse");
+                CoapResponse response = (CoapResponse) msg;
+
+                // If response contains path, add di
+                if (response.getOption(11) != null) {
+                    response.getOption(11).add(0,
+                            sessionManager.queryDid(ctx).getBytes());
+                }
 
-                Logger.i("ctx.channel : "
-                        + ctx.attr(keyDevice).get().channel().toString());
-                ctx.attr(keyDevice).get().writeAndFlush(msg);
+                Logger.i(
+                        "ctx.channel : " + resourceClient.channel().toString());
+                resourceClient.writeAndFlush(response);
                 return;
             }
         }
index 4856855..4d60239 100644 (file)
@@ -14,6 +14,7 @@ import org.iotivity.cloud.base.protocols.coap.CoapRequest;
 import org.iotivity.cloud.base.protocols.coap.CoapResponse;
 import org.iotivity.cloud.base.protocols.coap.enums.CoapMethod;
 import org.iotivity.cloud.ciserver.Constants;
+import org.iotivity.cloud.ciserver.protocols.CoapAuthHandler;
 import org.iotivity.cloud.ciserver.protocols.CoapRelayHandler;
 import org.iotivity.cloud.ciserver.resources.KeepAliveResource;
 import org.iotivity.cloud.util.Cbor;
@@ -73,6 +74,8 @@ public class TestCloudInterface {
         CoapClientHandler coapHandler = new CoapClientHandler();
         coapClient.addHandler(coapHandler);
 
+        coapClient.addHandler(new CoapAuthHandler("127.0.0.1", 5683));
+
         coapClient.startClient(new InetSocketAddress("127.0.0.1", 5683));
 
         return coapHandler.connectCtx;
@@ -199,6 +202,24 @@ public class TestCloudInterface {
     }
 
     @Test
+    public void TestAuthURI() throws Exception {
+
+        CoapRequest request = new CoapRequest(CoapMethod.GET);
+        request.setUriPath(Constants.AUTH_URI);
+        request.setUriQuery("rt=oic.wk.rdpub");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+        makePayload(request);
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+
+        coapClient.sendRequest(request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
     public void TestRequestGetMessageToDeviceCIOwner() throws Exception {
 
         CoapRequest request = new CoapRequest(CoapMethod.GET);
@@ -251,5 +272,4 @@ public class TestCloudInterface {
         coapServer.stopServer();
         coapClient.stopClient();
     }
-
 }
index 36eadcb..c283f66 100644 (file)
@@ -17,7 +17,7 @@ Build and Run
 
 4) Build a .jar file
 
-       $ mvn install
+       $ mvn install -Dmaven.test.skip=true
 
        - The CloudResourceDirectory-0.0.1-SNAPSHOT.jar file will be placed in the "target" folder
 
index 29fed8f..f39e048 100644 (file)
@@ -27,18 +27,12 @@ import org.iotivity.cloud.base.CoapServer;
 import org.iotivity.cloud.base.ResourceManager;
 import org.iotivity.cloud.rdserver.resources.ResourceDirectoryResource;
 import org.iotivity.cloud.util.Logger;
-import org.iotivity.cloud.util.Net;
 
 public class ResourceDirectoryServer {
 
     public static void main(String[] args) throws Exception {
 
         System.out.println("-----RD SERVER-----");
-        String hostAddress = Net.getMyIpAddress();
-        if (hostAddress.equals("") == true) {
-            Logger.e("cannot find host address.");
-            return;
-        }
 
         if (args.length != 1) {
             Logger.e("coap server port required");
index 5f51c88..7a4ae09 100644 (file)
@@ -42,7 +42,7 @@ cc_sample_app_env.AppendUnique(CPPPATH = [
 cc_sample_app_env.AppendUnique(CXXFLAGS = ['-O2', '-g', '-Wall', '-Wextra', '-std=c++0x', '-pthread'])
 cc_sample_app_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
 cc_sample_app_env.AppendUnique(RPATH = [env.get('BUILD_DIR')])
-cc_sample_app_env.PrependUnique(LIBS = ['octbstack'])
+cc_sample_app_env.PrependUnique(LIBS = ['octbstack', 'pthread'])
 
 ######################################################################
 # Source files and Targets
index 342c46d..06b3fed 100644 (file)
@@ -19,9 +19,7 @@
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
 ///
-/// This sample provides steps to define an interface for a resource
-/// (properties and methods) and host this resource on the server.
-/// Additionally, it'll have a client example to discover it as well.
+/// This sample provides the way to create cloud sample
 ///
 #include <memory>
 #include <iostream>
@@ -30,6 +28,7 @@
 #include <map>
 #include <vector>
 #include <string>
+#include <pthread.h>
 
 #include "ocstack.h"
 #include "ocpayload.h"
@@ -48,11 +47,10 @@ typedef struct LIGHTRESOURCE
     bool state;
     int power;
 } LightResource;
-static LightResource Light;
 static LightResource gLightInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
 
 
-OCRepPayload *getPayload(const char *uri, int64_t power, bool state)
+OCRepPayload *responsePayload(int64_t power, bool state)
 {
     OCRepPayload *payload = OCRepPayloadCreate();
     if (!payload)
@@ -61,40 +59,50 @@ OCRepPayload *getPayload(const char *uri, int64_t power, bool state)
         return nullptr;
     }
 
-    OCRepPayloadSetUri(payload, uri);
     OCRepPayloadSetPropBool(payload, "state", state);
     OCRepPayloadSetPropInt(payload, "power", power);
 
     return payload;
 }
 
-
 OCRepPayload *constructResponse(OCEntityHandlerRequest *ehRequest)
 {
-    char *resourceUri = NULL;
-
     if (ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
     {
         std::cout << "Incoming payload not a representation" << std::endl;
         return nullptr;
     }
 
-    LightResource *currLightResource = &Light;
+    LightResource *currLightResource = NULL;
 
     if (ehRequest->resource == gLightInstance[0].handle)
     {
         currLightResource = &gLightInstance[0];
-        resourceUri = (char *) "/a/light/0";
     }
     else if (ehRequest->resource == gLightInstance[1].handle)
     {
         currLightResource = &gLightInstance[1];
-        resourceUri = (char *) "/a/light/1";
     }
 
-    std::cout << "Resource URI " << resourceUri << std::endl;
+    if (OC_REST_PUT == ehRequest->method)
+    {
+        // Get pointer to query
+        int64_t pow;
+        OCRepPayload *input = reinterpret_cast<OCRepPayload *>(ehRequest->payload);
 
-    return getPayload(resourceUri, currLightResource->power, currLightResource->state);
+        if (OCRepPayloadGetPropInt(input, "power", &pow))
+        {
+            currLightResource->power = pow;
+        }
+
+        bool state;
+        if (OCRepPayloadGetPropBool(input, "state", &state))
+        {
+            currLightResource->state = state;
+        }
+    }
+
+    return responsePayload(currLightResource->power, currLightResource->state);
 }
 
 OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest,
@@ -112,6 +120,105 @@ OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest,
     return OC_EH_OK;
 }
 
+OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest,
+                                        OCRepPayload **payload)
+{
+    OCEntityHandlerResult ehResult;
+    OCRepPayload *putResp = constructResponse(ehRequest);
+
+    if (!putResp)
+    {
+        std::cout << "Failed to construct Json response" << std::endl;
+        return OC_EH_ERROR;
+    }
+
+    *payload = putResp;
+    ehResult = OC_EH_OK;
+
+    return ehResult;
+}
+
+#define SAMPLE_MAX_NUM_OBSERVATIONS  2
+static bool observeThreadStarted = false;
+int gLightUnderObservation = 0;
+pthread_t threadId_observe;
+typedef struct
+{
+    OCObservationId observationId;
+    bool valid;
+    OCResourceHandle resourceHandle;
+} Observers;
+Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
+
+void *ChangeLightRepresentation(void *param)
+{
+    (void)param;
+    OCStackResult result = OC_STACK_ERROR;
+
+    while (true)
+    {
+        sleep(3);
+        gLightInstance[0].power += 1;
+        gLightInstance[1].power += 3;
+
+        if (gLightUnderObservation)
+        {
+            std::cout << " =====> Notifying stack of new power level " << gLightInstance[0].power << std::endl;
+            std::cout << " =====> Notifying stack of new power level " << gLightInstance[1].power << std::endl;
+            // Notifying all observers
+            result = OCNotifyAllObservers(gLightInstance[0].handle, OC_NA_QOS);
+            result = OCNotifyAllObservers(gLightInstance[1].handle, OC_NA_QOS);
+
+            std::cout << " =====> Notifying result " << result << std::endl;
+        }
+    }
+    return NULL;
+}
+
+void ProcessObserveRegister(OCEntityHandlerRequest *ehRequest)
+{
+    std::cout << "Received observation registration request with observation Id " <<
+              ehRequest->obsInfo.obsId << std::endl;
+
+    if (!observeThreadStarted)
+    {
+        pthread_create(&threadId_observe, NULL, ChangeLightRepresentation, (void *)NULL);
+        observeThreadStarted = 1;
+    }
+    for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
+    {
+        if (interestedObservers[i].valid == false)
+        {
+            interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
+            interestedObservers[i].valid = true;
+            gLightUnderObservation = 1;
+            break;
+        }
+    }
+}
+
+void ProcessObserveDeregister(OCEntityHandlerRequest *ehRequest)
+{
+    bool clientStillObserving = false;
+
+    std::cout << "Received observation deregistration request for observation Id " <<
+              ehRequest->obsInfo.obsId << std::endl;
+    for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
+    {
+        if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
+        {
+            interestedObservers[i].valid = false;
+        }
+        if (interestedObservers[i].valid == true)
+        {
+            // Even if there is one single client observing we continue notifying entity handler
+            clientStillObserving = true;
+        }
+    }
+    if (clientStillObserving == false)
+        gLightUnderObservation = 0;
+}
+
 OCEntityHandlerResult
 OCEntityHandlerCb(OCEntityHandlerFlag flag,
                   OCEntityHandlerRequest *entityHandlerRequest, void * /*callback*/)
@@ -142,6 +249,11 @@ OCEntityHandlerCb(OCEntityHandlerFlag flag,
             std::cout << "Received OC_REST_GET from client" << std::endl;
             ehResult = ProcessGetRequest(entityHandlerRequest, &payload);
         }
+        else if (OC_REST_PUT == entityHandlerRequest->method)
+        {
+            std::cout << "Received OC_REST_PUT from client" << std::endl;
+            ehResult = ProcessPutRequest(entityHandlerRequest, &payload);
+        }
         else
         {
             std::cout << "Received unsupported method %d from client " << entityHandlerRequest->method <<
@@ -168,6 +280,21 @@ OCEntityHandlerCb(OCEntityHandlerFlag flag,
         }
     }
 
+    if (flag & OC_OBSERVE_FLAG)
+    {
+        std::cout << "Flag includes OC_OBSERVE_FLAG" << std::endl;
+        if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
+        {
+            std::cout << "Received OC_OBSERVE_REGISTER from client" << std::endl;
+            ProcessObserveRegister(entityHandlerRequest);
+        }
+        else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
+        {
+            std::cout << "Received OC_OBSERVE_DEREGISTER from client" << std::endl;
+            ProcessObserveDeregister(entityHandlerRequest);
+        }
+    }
+
     OCPayloadDestroy(response.payload);
     return ehResult;
 }
@@ -238,6 +365,183 @@ void PublishResources(std::string host, std::string additionalQuery)
 ////////////////////////////////////////Client Sample
 std::string g_host = "coap+tcp://";
 
+void PrintRepresentation(OCRepPayloadValue *val)
+{
+    while (val)
+    {
+        std::cout << "Key: " << val->name << " Value: ";
+        switch (val->type)
+        {
+            case OCREP_PROP_NULL:
+                std::cout << "NULL" << std::endl;
+                break;
+
+            case OCREP_PROP_INT:
+                std::cout << val->i << std::endl;
+                break;
+
+            case OCREP_PROP_DOUBLE:
+                std::cout << val->d << std::endl;
+                break;
+
+            case OCREP_PROP_BOOL:
+                std::cout << val->b << std::endl;
+                break;
+
+            case OCREP_PROP_STRING:
+                std::cout << val->str << std::endl;
+                break;
+
+            case OCREP_PROP_BYTE_STRING:
+                std::cout << "[ByteString]" << std::endl;
+                break;
+
+            case OCREP_PROP_OBJECT:
+                std::cout << "[Object]" << std::endl;
+                break;
+
+            case OCREP_PROP_ARRAY:
+                std::cout << "[Array]" << std::endl;
+                break;
+        }
+
+        val = val->next;
+    }
+}
+
+
+int gNumObserveNotifies = 0;
+
+OCStackApplicationResult obsReqCB(void *ctx, OCDoHandle handle,
+                                  OCClientResponse *clientResponse)
+{
+    std::cout << "Observe response received from " << clientResponse->resourceUri << std::endl;
+
+    if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
+    {
+        std::cout << "Invalid Put callback received" << std::endl;
+    }
+
+    if (clientResponse)
+    {
+        if (clientResponse->payload == NULL)
+        {
+            std::cout << "No payload received" << std::endl;
+        }
+
+        OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
+
+        PrintRepresentation(val);
+
+        gNumObserveNotifies++;
+        if (gNumObserveNotifies > 5) //large number to test observing in DELETE case.
+        {
+            std::cout << "Cancelling with OC_HIGH_QOS" << std::endl;
+            if (OCCancel(handle, OC_HIGH_QOS, NULL, 0) != OC_STACK_OK)
+            {
+                std::cout << "Observe cancel error" << std::endl;
+            }
+        }
+        if (clientResponse->sequenceNumber == OC_OBSERVE_REGISTER)
+        {
+            std::cout << "This also serves as a registration confirmation" << std::endl;
+        }
+        else if (clientResponse->sequenceNumber == OC_OBSERVE_DEREGISTER)
+        {
+            std::cout << "This also serves as a deregistration confirmation" << std::endl;
+            return OC_STACK_DELETE_TRANSACTION;
+        }
+        else if (clientResponse->sequenceNumber == OC_OBSERVE_NO_OPTION)
+        {
+            std::cout << "This also tells you that registration/deregistration failed" << std::endl;
+            return OC_STACK_DELETE_TRANSACTION;
+        }
+    }
+    else
+    {
+        std::cout << "obsReqCB received Null clientResponse" << std::endl;
+    }
+
+    return OC_STACK_KEEP_TRANSACTION;
+}
+
+void ObserveResource(std::string uri, std::string additionalQuery)
+{
+    OCCallbackData cbData;
+    cbData.cb = obsReqCB;
+    cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
+    cbData.cd = NULL;
+
+    uri += additionalQuery;
+
+    std::cout << "Request OBSERVE to resource " << uri.c_str() << std::endl;
+
+    OCStackResult res = OCDoResource(NULL, OC_REST_OBSERVE, uri.c_str(), NULL, NULL,
+                                     CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
+
+    std::cout << "Requesting OBSERVE res=" << res << std::endl;
+}
+
+OCStackApplicationResult putReqCB(void *ctx, OCDoHandle /*handle*/,
+                                  OCClientResponse *clientResponse)
+{
+    std::cout << "Put response received from " << clientResponse->resourceUri << std::endl;
+
+    if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
+    {
+        std::cout << "Invalid Put callback received" << std::endl;
+    }
+
+    if (clientResponse->payload == NULL)
+    {
+        std::cout << "No payload received" << std::endl;
+    }
+
+    OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
+
+    PrintRepresentation(val);
+
+    std::string requestUri = g_host;
+    requestUri += clientResponse->resourceUri;
+
+    ObserveResource(requestUri, "");
+
+    return OC_STACK_KEEP_TRANSACTION;
+}
+
+OCPayload *putRequestPayload()
+{
+    OCRepPayload *payload = OCRepPayloadCreate();
+
+    if (!payload)
+    {
+        std::cout << "Failed to create put payload object" << std::endl;
+        std::exit(1);
+    }
+
+    OCRepPayloadSetPropInt(payload, "power", 15);
+    OCRepPayloadSetPropBool(payload, "state", true);
+
+    return (OCPayload *)payload;
+}
+
+void PutResource(std::string uri, std::string additionalQuery)
+{
+    OCCallbackData cbData;
+    cbData.cb = putReqCB;
+    cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
+    cbData.cd = NULL;
+
+    uri += additionalQuery;
+
+    std::cout << "Request PUT to resource " << uri.c_str() << std::endl;
+
+    OCStackResult res = OCDoResource(NULL, OC_REST_PUT, uri.c_str(), NULL, putRequestPayload(),
+                                     CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
+
+    std::cout << "Requesting PUT res=" << res << std::endl;
+}
+
 OCStackApplicationResult handleGetCB(void *ctx,
                                      OCDoHandle /*handle*/,
                                      OCClientResponse *clientResponse)
@@ -246,62 +550,45 @@ OCStackApplicationResult handleGetCB(void *ctx,
 
     if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
     {
-        std::cout << "Invalid Publish callback received" << std::endl;
+        std::cout << "Invalid Get callback received" << std::endl;
     }
 
     if (clientResponse->payload == NULL)
+    {
         std::cout << "No payload received" << std::endl;
+    }
 
     if (clientResponse->payload != NULL &&
         clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
     {
-        std::cout << "PAYLOAD_TYPE_REPRESENTATION received" << std::endl;
-
         OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
 
-        while (val)
-        {
-            std::cout << "Key: " << val->name << " Value: ";
-            switch (val->type)
-            {
-                case OCREP_PROP_NULL:
-                    std::cout << "NULL" << std::endl;
-                    break;
-
-                case OCREP_PROP_INT:
-                    std::cout << val->i << std::endl;
-                    break;
+        PrintRepresentation(val);
 
-                case OCREP_PROP_DOUBLE:
-                    std::cout << val->d << std::endl;
-                    break;
+        std::string requestUri = g_host;
+        requestUri += clientResponse->resourceUri;
 
-                case OCREP_PROP_BOOL:
-                    std::cout << val->b << std::endl;
-                    break;
+        PutResource(requestUri, "");
+    }
 
-                case OCREP_PROP_STRING:
-                    std::cout << val->str << std::endl;
-                    break;
+    return OC_STACK_KEEP_TRANSACTION;
+}
 
-                case OCREP_PROP_BYTE_STRING:
-                    std::cout << "[ByteString]" << std::endl;
-                    break;
+void GetResource(std::string uri, std::string additionalQuery)
+{
+    OCCallbackData cbData;
+    cbData.cb = handleGetCB;
+    cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
+    cbData.cd = NULL;
 
-                case OCREP_PROP_OBJECT:
-                    std::cout << "[Object]" << std::endl;
-                    break;
+    uri += additionalQuery;
 
-                case OCREP_PROP_ARRAY:
-                    std::cout << "[Array]" << std::endl;
-                    break;
-            }
+    std::cout << "Request GET to resource " << uri.c_str() << std::endl;
 
-            val = val->next;
-        }
-    }
+    OCStackResult res = OCDoResource(NULL, OC_REST_GET, uri.c_str(), NULL, NULL,
+                                     CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
 
-    return OC_STACK_KEEP_TRANSACTION;
+    std::cout << "Requesting GET res=" << res << std::endl;
 }
 
 // This is a function called back when a device is discovered
@@ -331,23 +618,14 @@ OCStackApplicationResult discoveryReqCB(void *ctx, OCDoHandle /*handle*/,
             return OC_STACK_DELETE_TRANSACTION;
         }
 
-        OCCallbackData cbData;
-        cbData.cb = handleGetCB;
-        cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
-        cbData.cd = NULL;
-
         while (resource)
         {
             std::cout << "Found Resource " << resource->uri << std::endl;
+
             std::string requestUri = g_host;
             requestUri += resource->uri;
 
-            std::cout << "Request GET to resource " << requestUri.c_str() << std::endl;
-
-            OCStackResult res = OCDoResource(NULL, OC_REST_GET, requestUri.c_str(), NULL, NULL,
-                                             CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
-
-            std::cout << "Requesting GET res=" << res << std::endl;
+            GetResource(requestUri, "");
 
             resource = resource->next;
         }
@@ -395,7 +673,7 @@ OCStackApplicationResult handleLoginoutCB(void *ctx,
 {
     if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
     {
-        std::cout << "Invalid Login callback received" << std::endl;
+        std::cout << "Invalid Login/out callback received" << std::endl;
     }
 
     std::cout << "Login/out response received code: " << clientResponse->result << std::endl;
@@ -483,6 +761,8 @@ int main(int argc, char *argv[])
     std::string authProvider;
     std::string authCode;
 
+    OCMode      stackMode = OC_CLIENT;
+
     switch (argc)
     {
         case 2:
@@ -495,9 +775,14 @@ int main(int argc, char *argv[])
         case 4:
             session = argv[2];
             if (argv[3][0] == 's')
+            {
+                stackMode = OC_CLIENT_SERVER;
                 g_runningMode = 1;
+            }
             else if (argv[3][0] == 'c')
+            {
                 g_runningMode = 2;
+            }
             break;
 
         default:
@@ -509,14 +794,14 @@ int main(int argc, char *argv[])
 
     std::cout << "Host " << g_host.c_str() << std::endl;
 
-    OCStackResult   res = OC_STACK_ERROR;
-
-    if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK)
+    if (OCInit(NULL, 0, stackMode) != OC_STACK_OK)
     {
         std::cout << "OCStack init error" << std::endl;
         return 0;
     }
 
+    OCStackResult   res = OC_STACK_ERROR;
+
     switch (argc)
     {
         case 2:
index fd933aa..3a376a6 100644 (file)
@@ -23,10 +23,9 @@ package org.iotivity.cloud.base;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
-
-import org.iotivity.cloud.util.Logger;
+import java.util.Map.Entry;
+import java.util.Objects;
 
 import io.netty.channel.ChannelHandlerContext;
 
@@ -48,22 +47,10 @@ public class SessionManager {
     }
 
     public void removeSessionByChannel(ChannelHandlerContext ctx) {
-        synchronized (sessions) {
-            if (!isThereCtxChannel(ctx)) {
-                Logger.d("Already Session Removed : "
-                        + ctx.channel().toString());
-                return;
-            }
-            Iterator<String> iterator = sessions.keySet().iterator();
-            while (iterator.hasNext()) {
-                String key = (String) iterator.next();
-                if (ctx.channel().toString()
-                        .equals(querySession(key).channel().toString())) {
-                    Logger.d("Session Remove : " + ctx.channel().toString());
-                    removeSession(key);
-                    break;
-                }
-            }
+
+        String did = queryDid(ctx);
+        if (did != null) {
+            removeSession(did);
         }
     }
 
@@ -77,19 +64,17 @@ public class SessionManager {
         return ctx;
     }
 
-    private boolean isThereCtxChannel(ChannelHandlerContext ctx) {
-
+    public String queryDid(ChannelHandlerContext ctx) {
         synchronized (sessions) {
-            Iterator<String> iterator = sessions.keySet().iterator();
-            while (iterator.hasNext()) {
-                String key = (String) iterator.next();
-                if (ctx.channel().toString()
-                        .equals(querySession(key).channel().toString())) {
-                    return true;
+            for (Entry<String, ChannelHandlerContext> entry : sessions
+                    .entrySet()) {
+                if (Objects.equals(ctx, entry.getValue())) {
+                    return entry.getKey();
                 }
             }
-            return false;
         }
+
+        return null;
     }
 
     public List<String> getSessions() {
index f047fd8..2aee0dd 100644 (file)
@@ -100,9 +100,16 @@ public class CoapEncoder extends MessageToByteEncoder<CoapMessage> {
         for (int i = 0; i < 40; i++) {
             List<byte[]> values = coapMessage.getOption(i);
             if (values != null) {
-                for (byte[] value : values) {
-                    writeOption(i - preOptionNum,
-                            value != null ? value.length : 0, byteBuf, value);
+                if (values.size() > 0) {
+                    for (byte[] value : values) {
+                        writeOption(i - preOptionNum,
+                                value != null ? value.length : 0, byteBuf,
+                                value);
+                        preOptionNum = i;
+                    }
+
+                } else {
+                    writeOption(i - preOptionNum, 0, byteBuf, null);
                     preOptionNum = i;
                 }
             }
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/util/Net.java b/cloud/stack/src/main/java/org/iotivity/cloud/util/Net.java
deleted file mode 100644 (file)
index e6804fb..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * //******************************************************************
- * //
- * // Copyright 2016 Samsung Electronics 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.cloud.util;
-
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Enumeration;
-
-public class Net {
-
-    public static String getMyIpAddress() {
-
-        try {
-            for (Enumeration<NetworkInterface> en = NetworkInterface
-                    .getNetworkInterfaces(); en.hasMoreElements();) {
-                NetworkInterface intf = en.nextElement();
-                for (Enumeration<InetAddress> enumIpAddr = intf
-                        .getInetAddresses(); enumIpAddr.hasMoreElements();) {
-                    InetAddress inetAddress = enumIpAddr.nextElement();
-                    if (!inetAddress.isLoopbackAddress()
-                            && !inetAddress.isLinkLocalAddress()
-                            && inetAddress.isSiteLocalAddress()) {
-                        return inetAddress.toString();
-                    }
-                }
-            }
-        } catch (SocketException ex) {
-            Logger.e("SocketException", ex);
-        }
-
-        return "";
-    }
-}
diff --git a/cloud/stack/src/test/java/org/iotivity/cloud/util/UtilTest.java b/cloud/stack/src/test/java/org/iotivity/cloud/util/UtilTest.java
new file mode 100644 (file)
index 0000000..9727a4a
--- /dev/null
@@ -0,0 +1,63 @@
+package org.iotivity.cloud.util;
+
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+
+import org.iotivity.cloud.base.CoapClient;
+import org.iotivity.cloud.base.CoapServer;
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+import org.iotivity.cloud.base.protocols.coap.enums.CoapMethod;
+import org.junit.Test;
+
+public class UtilTest {
+
+    @Test
+    public void testCbor() {
+        Cbor<HashMap<String, String>> cbor = new Cbor<HashMap<String, String>>();
+
+        HashMap<String, String> setpayloadData = new HashMap<String, String>();
+        setpayloadData.put("test", "test");
+
+        byte[] cborData = cbor.encodingPayloadToCbor(setpayloadData);
+
+        HashMap<String, String> getpayloadData = null;
+        getpayloadData = cbor.parsePayloadFromCbor(cborData,
+                new HashMap<String, String>().getClass());
+    }
+
+    @Test
+    public void testCoapLogHandler() throws Exception {
+        CoapServer server = new CoapServer();
+        server.startServer(new InetSocketAddress(5683));
+        server.addHandler(new CoapLogHandler());
+
+        CoapClient client = new CoapClient();
+        client.addHandler(new CoapLogHandler());
+        client.startClient(new InetSocketAddress("127.0.0.1", 5683));
+
+        CoapRequest request = new CoapRequest(CoapMethod.PUT);
+        client.sendRequest(request);
+
+        client.stopClient();
+        server.stopServer();
+    }
+
+    @Test
+    public void testJSONUtil() throws Exception {
+        HashMap<Object, Object> setpayloadData = new HashMap<Object, Object>();
+        setpayloadData.put("test", "test");
+
+        String msg = JSONUtil.writeJSON(setpayloadData);
+        JSONUtil.parseJSON(msg, "test");
+        JSONUtil.parseJSON(msg);
+    }
+
+    @Test
+    public void testLogger() throws Exception {
+        Logger.v("VERBOSE test");
+        Logger.d("DEBUG test");
+        Logger.i("INFO test");
+        Logger.e("ERROR test");
+        Logger.w("WARNING test");
+    }
+}