IoTivity Cloud feature
authorJee Hyeok Kim <jihyeok13.kim@samsung.com>
Fri, 26 Feb 2016 10:57:03 +0000 (19:57 +0900)
committerJee Hyeok Kim <jihyeok13.kim@samsung.com>
Sun, 6 Mar 2016 22:59:47 +0000 (22:59 +0000)
Change-Id: I27cb0613e65341f2b60570b63132e0b02549a629
Signed-off-by: jk13 <jihyeok13.kim@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/5021
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
73 files changed:
cloud/.gitignore [new file with mode: 0644]
cloud/README [new file with mode: 0644]
cloud/account/.classpath [new file with mode: 0644]
cloud/account/.gitignore [new file with mode: 0644]
cloud/account/.project [new file with mode: 0644]
cloud/account/README [new file with mode: 0644]
cloud/account/pom.xml [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/AccountServer.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/AccountServerManager.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/Const.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/AccountDBManager.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/MongoDB.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/UserDevice.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/UserSession.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/oauth/GitHub.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/oauth/OAuthServer.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/AccountResource.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/AuthResource.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/ResponseObject.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/util/CoapMessageBuilder.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/util/JSONUtil.java [new file with mode: 0644]
cloud/account/src/test/java/org/iotivity/cloud/testaccountserver/TestAccountServer.java [new file with mode: 0644]
cloud/interface/.classpath [new file with mode: 0644]
cloud/interface/.gitignore [new file with mode: 0644]
cloud/interface/.project [new file with mode: 0644]
cloud/interface/README [new file with mode: 0644]
cloud/interface/pom.xml [new file with mode: 0644]
cloud/interface/src/main/java/org/iotivity/cloud/ciserver/CloudInterfaceServer.java [new file with mode: 0644]
cloud/interface/src/main/java/org/iotivity/cloud/ciserver/Constants.java [new file with mode: 0644]
cloud/interface/src/main/java/org/iotivity/cloud/ciserver/protocols/CoapAuthHandler.java [new file with mode: 0644]
cloud/interface/src/main/java/org/iotivity/cloud/ciserver/protocols/CoapRelayHandler.java [new file with mode: 0644]
cloud/interface/src/main/java/org/iotivity/cloud/ciserver/resources/KeepAliveResource.java [new file with mode: 0644]
cloud/resourcedirectory/.classpath [new file with mode: 0644]
cloud/resourcedirectory/.gitignore [new file with mode: 0644]
cloud/resourcedirectory/.project [new file with mode: 0644]
cloud/resourcedirectory/README [new file with mode: 0644]
cloud/resourcedirectory/pom.xml [new file with mode: 0644]
cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/Constants.java [new file with mode: 0644]
cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/JSONUtil.java [new file with mode: 0644]
cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/MongoDB.java [new file with mode: 0644]
cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/ResourceDirectoryServer.java [new file with mode: 0644]
cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/resources/LinksPayloadFormat.java [new file with mode: 0644]
cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/resources/PublishPayloadFormat.java [new file with mode: 0644]
cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/resources/ResourceDirectoryResource.java [new file with mode: 0644]
cloud/resourcedirectory/src/test/java/org/iotivity/cloud/testrdserver/RDServerTest.java [new file with mode: 0644]
cloud/stack/.classpath [new file with mode: 0644]
cloud/stack/.gitignore [new file with mode: 0644]
cloud/stack/.project [new file with mode: 0644]
cloud/stack/README [new file with mode: 0644]
cloud/stack/pom.xml [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/CoapClient.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/CoapServer.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/HttpClient.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/HttpServer.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/Resource.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/ResourceManager.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/SessionManager.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapDecoder.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapEncoder.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapMessage.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapRequest.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapResponse.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/enums/CoapMethod.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/enums/CoapOption.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/enums/CoapStatus.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/proxy/CoapHttpProxyHandler.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/util/Cbor.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/util/CoapLogHandler.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/util/JSONUtil.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/util/Logger.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/util/Net.java [new file with mode: 0644]
cloud/stack/src/test/java/org/iotivity/cloud/base/CoapClientTest.java [new file with mode: 0644]
cloud/stack/src/test/java/org/iotivity/cloud/base/CoapServerTest.java [new file with mode: 0644]

diff --git a/cloud/.gitignore b/cloud/.gitignore
new file mode 100644 (file)
index 0000000..9f1d3ca
--- /dev/null
@@ -0,0 +1,2 @@
+/target/
+*.class
\ No newline at end of file
diff --git a/cloud/README b/cloud/README
new file mode 100644 (file)
index 0000000..81b45a2
--- /dev/null
@@ -0,0 +1,18 @@
+This project contains series of modules for building cloud services.
+
+Modules
+
+1. stack - Java 1.7 based CoAP over TCP implementation.
+2. interface - cloud interface server that accept incoming IoTivity clients connection.
+3. resource_directory - resource directory server that store clients resource models.
+4. account - account server that handle clients credential using OAuth2.
+5. samples - sample IoTivity clients that show how clients working with cloud.
+
+Each cloud modules has README file how to install and run.
+You can run each modules on single computer or PAAS.
+
+Note. resource_directory should launched before interface and account.
+
+Architecture
+client--------interface_server--------resource_directory_server--------mongo_db
+                      \---------------account_server-------------------mongo_db
\ No newline at end of file
diff --git a/cloud/account/.classpath b/cloud/account/.classpath
new file mode 100644 (file)
index 0000000..f619a53
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="target/classes" path="src/main/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/cloud/account/.gitignore b/cloud/account/.gitignore
new file mode 100644 (file)
index 0000000..b83d222
--- /dev/null
@@ -0,0 +1 @@
+/target/
diff --git a/cloud/account/.project b/cloud/account/.project
new file mode 100644 (file)
index 0000000..336bb80
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>CloudAccount</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.m2e.core.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.m2e.core.maven2Nature</nature>
+       </natures>
+</projectDescription>
diff --git a/cloud/account/README b/cloud/account/README
new file mode 100644 (file)
index 0000000..4e7a0b9
--- /dev/null
@@ -0,0 +1,29 @@
+This project contains the Account Server code.
+
+
+Build and Run
+
+1) Install Apache Maven if you don't have it
+
+       http://maven.apache.org
+
+2) Build a CloudStack. If you are building first time, then build the stack.
+
+       go to "stack" folder in root directory
+       $ mvn install
+
+3) Build a .jar file
+
+       $ mvn install
+
+       - The CloudAccount-0.0.1-SNAPSHOT.jar file will be placed in the "target" folder
+
+4) Run .jar file
+
+       go to "target" folder
+       $ java -jar CloudAccount-0.0.1-SNAPSHOT.jar arg1(AccountServer CoAP Server Port)
+       e.g. java -jar CloudAccount-0.0.1-SNAPSHOT.jar 5685
+
+       - Before you run a Accout server, You need to set up following steps.
+          1) Install MongoDB
+          2) Install Github certificates for github.com and *.github.com.
diff --git a/cloud/account/pom.xml b/cloud/account/pom.xml
new file mode 100644 (file)
index 0000000..e4d08ab
--- /dev/null
@@ -0,0 +1,79 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.iotivity.cloud</groupId>
+  <artifactId>CloudAccount</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  
+  <properties>
+               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+       </properties>
+       
+  <dependencies>
+               <dependency>
+                       <groupId>org.iotivity.cloud</groupId>
+                       <artifactId>CloudStack</artifactId>
+                       <version>0.0.1-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.mongodb</groupId>
+                       <artifactId>mongo-java-driver</artifactId>
+                       <version>3.2.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <version>4.12</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.oltu.oauth2</groupId>
+                       <artifactId>org.apache.oltu.oauth2.client</artifactId>
+                       <version>1.0.1</version>
+               </dependency>
+  </dependencies>
+       
+  <build>
+               <plugins>
+                       <plugin>
+                               <inherited>true</inherited>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <configuration>
+                                       <source>1.7</source>
+                                       <target>1.7</target>
+                                       <encoding>UTF-8</encoding>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-jar-plugin</artifactId>
+                               <configuration>
+                                       <archive>
+                                               <manifest>
+                                                       <mainClass>org.iotivity.cloud.accountserver.AccountServer</mainClass>
+                                                       <addClasspath>true</addClasspath>
+                                                       <classpathPrefix>lib/</classpathPrefix>
+                                               </manifest>
+                                       </archive>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-dependency-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                               <id>copy-dependencies</id>
+                                               <phase>package</phase>
+                                               <goals>
+                                                       <goal>copy-dependencies</goal>
+                                               </goals>
+                                       </execution>
+                               </executions>
+                               <configuration>
+                                       <outputDirectory>target/lib</outputDirectory>
+                                       <overWriteIfNewer>true</overWriteIfNewer>
+                               </configuration>
+                       </plugin>
+               </plugins>              
+       </build>
+  
+</project>
\ No newline at end of file
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/AccountServer.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/AccountServer.java
new file mode 100644 (file)
index 0000000..12b233e
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver;
+
+import java.net.InetSocketAddress;
+
+import org.iotivity.cloud.accountserver.resources.AccountResource;
+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;
+
+/**
+ * 
+ * This class is in charge of running account server.
+ * 
+ */
+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");
+            return;
+        }
+
+        ResourceManager resourceManager = null;
+
+        CoapServer coapServer = null;
+
+        coapServer = new CoapServer();
+
+        resourceManager = new ResourceManager();
+        coapServer.addHandler(resourceManager);
+
+        resourceManager.registerResource(new AuthResource());
+        resourceManager.registerResource(new AccountResource());
+
+        coapServer
+                .startServer(new InetSocketAddress(Integer.parseInt(args[0])));
+    }
+
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/AccountServerManager.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/AccountServerManager.java
new file mode 100644 (file)
index 0000000..4be8fb7
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+import org.iotivity.cloud.accountserver.db.AccountDBManager;
+import org.iotivity.cloud.accountserver.oauth.GitHub;
+import org.iotivity.cloud.util.Logger;
+
+/**
+ *
+ * This class provides a set of API to handle requests for registering account
+ * information of authorized user, and publishing and finding resources.
+ *
+ */
+public class AccountServerManager {
+
+    public Boolean registerUserAccount(String userId, String deviceId) {
+
+        Boolean ret = false;
+
+        // store info to OAuthDBManager
+        ret = AccountDBManager.getInstance().registerUserDevice(userId,
+                deviceId);
+
+        return ret;
+    }
+
+    public String registerUserAccount(String userId) {
+
+        String sessionCode = null;
+        sessionCode = generateSessionCode();
+
+        // store info to OAuthDBManager
+        AccountDBManager.getInstance().registerUserSessionCode(userId,
+                sessionCode);
+
+        return sessionCode;
+    }
+
+    /**
+     * API for requesting user identifier to interested authorization server
+     * 
+     * @param accessToeken
+     *            access token
+     * @param authServer
+     *            authorization server
+     * @return String - user identifier
+     */
+    public String requestUserId(String authCode, String authServer) {
+
+        String userId = null;
+
+        String accessToken = getAccessToken(authCode, authServer);
+        userId = getUserId(accessToken, authServer);
+
+        return userId;
+    }
+
+    public String requestUserId(String sessionCode) {
+
+        String userId = null;
+
+        // get userId from MongDB
+        userId = AccountDBManager.getInstance().getUserId(sessionCode);
+
+        return userId;
+    }
+
+    /**
+     * API for getting devices according to authorized user from database
+     * 
+     * @param userId
+     *            identifier of authorized user
+     * @return ArrayList<String> - list of devices
+     */
+    public ArrayList<String> requestAccountDevices(String userId) {
+
+        Logger.d("userId= " + userId);
+
+        ArrayList<String> deviceList = AccountDBManager.getInstance()
+                .getDevices(userId);
+
+        return deviceList;
+    }
+
+    /**
+     * API for requesting access token to interested authorization server
+     * 
+     * @param authServer
+     *            server name for authorization
+     * @param authCode
+     *            authorization code
+     * @return ArrayList<String> - array list of name of authorization servers
+     */
+    private String getAccessToken(String authCode, String authServer) {
+
+        String accessToken = null;
+
+        if (authServer.equals(Const.GITHUB)) {
+
+            GitHub gitHub = new GitHub();
+            accessToken = gitHub.requestAccessToken(authCode);
+
+        } else {
+
+            Logger.e("unsupported auth.server = " + authServer);
+        }
+
+        return accessToken;
+    }
+
+    private String getUserId(String accessToken, String authServer) {
+
+        String userId = null;
+
+        if (authServer.equals(Const.GITHUB)) {
+
+            GitHub gitHub = new GitHub();
+            userId = gitHub.requestGetUserInfo(accessToken);
+
+        } else {
+
+            Logger.e("unsupported auth.server = " + authServer);
+        }
+
+        return userId;
+    }
+
+    private String generateSessionCode() {
+
+        String sessionCode = "";
+
+        Random random = new Random();
+        int randomNum = random.nextInt(122);
+        char code;
+
+        // generate 16byte key with 0-9, A-Z, a-z
+        for (int k = 0; k < 16; k++) {
+            while (true) {
+                if ((randomNum >= 48 && randomNum <= 57)
+                        || (randomNum >= 65 && randomNum <= 90)
+                        || (randomNum >= 97 && randomNum <= 122)) {
+
+                    code = (char) randomNum;
+                    sessionCode += code;
+
+                    randomNum = random.nextInt(122);
+                    break;
+
+                } else {
+
+                    randomNum = random.nextInt(122);
+                }
+            }
+        }
+
+        return sessionCode;
+    }
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/Const.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/Const.java
new file mode 100644 (file)
index 0000000..33285fd
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver;
+
+public class Const {
+
+    // MongoDB
+    public static final String DEVICE_TABLE          = "USER_DEVICE";
+    public static final String SESSION_TABLE         = "USER_SESSION";
+    public static final String DB_NAME               = "ACCOUNTSERVER_DB";
+    public static final String USER_ID               = "userId";
+    public static final String DEVICE_ID             = "deviceId";
+    public static final String SESSION_CODE          = "sessionCode";
+
+    // Resource Uri
+    public static final String AUTH_URI              = "oic/auth";
+    public static final String ACCOUNT_URI           = "oic/account";
+
+    // query parameter
+    public static final String REQ_TYPE              = "reqtype";
+
+    // request type
+    public static final String TYPE_REGISTER         = "register";
+    public static final String TYPE_LOGIN            = "login";
+    public static final String TYPE_PUBLISH          = "publish";
+    public static final String TYPE_FIND             = "find";
+
+    // request payload
+    public static final String REQUEST_AUTH_CODE     = "authcode";
+    public static final String REQUEST_AUTH_SERVER   = "authprovider";
+    public static final String REQUEST_DEVICE_ID     = "deviceid";
+    public static final String REQUEST_USER_ID       = "userid";
+    public static final String REQUEST_SESSION_CODE  = "session";
+
+    // response
+    public static final String RESPONSE_SESSION_CODE = "session";
+    public static final String RESPONSE_USER_ID      = "userid";
+    public static final String RESPONSE_STATE        = "state";
+    public static final String RESPONSE_DEVICES      = "devices";
+
+    // auth servers
+    public static final String GITHUB                = "github";
+    public static final String GOOGLE                = "google";
+    public static final String FACEBOOK              = "facebook";
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/AccountDBManager.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/AccountDBManager.java
new file mode 100644 (file)
index 0000000..faba8fe
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.db;
+
+import java.util.ArrayList;
+
+import org.iotivity.cloud.accountserver.Const;
+
+/**
+ *
+ * This class provides a set of APIs managing database.
+ *
+ */
+public class AccountDBManager {
+
+    private static AccountDBManager accoutDBManager = new AccountDBManager();
+    private MongoDB                 mongoDB;
+
+    private AccountDBManager() {
+
+        try {
+
+            mongoDB = new MongoDB(Const.DB_NAME);
+
+            mongoDB.createTable(Const.DEVICE_TABLE);
+            mongoDB.createTable(Const.SESSION_TABLE);
+
+            registerAdminAccount();
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+        }
+    }
+
+    public static AccountDBManager getInstance() {
+
+        return accoutDBManager;
+    }
+
+    private void registerAdminAccount() {
+
+        String adminId = "admin";
+        String adminSessionCode = "00000000";
+
+        UserSession userSession = new UserSession();
+
+        userSession.setUserId(adminId);
+        userSession.setSessionCode(adminSessionCode);
+
+        mongoDB.createResource(userSession);
+        mongoDB.printResources();
+    }
+
+    /**
+     * API for storing session information of authorized user to mongoDB
+     * 
+     * @param userId
+     *            identifier of authorized user
+     * @param sessionCode
+     *            session code
+     * @return Boolean - true if stored, false if not
+     */
+    public Boolean registerUserSessionCode(String userId, String sessionCode) {
+
+        UserSession userSession = new UserSession();
+
+        userSession.setUserId(userId);
+        userSession.setSessionCode(sessionCode);
+
+        mongoDB.createResource(userSession);
+        mongoDB.printResources();
+
+        return true;
+    }
+
+    public Boolean registerUserDevice(String userId, String deviceId) {
+
+        UserDevice userDevice = new UserDevice();
+
+        userDevice.setUserId(userId);
+        userDevice.setDeviceId(deviceId);
+
+        mongoDB.createResource(userDevice);
+        mongoDB.printResources();
+
+        return true;
+    }
+
+    public String getUserId(String sessionCode) {
+
+        String userId = null;
+
+        userId = mongoDB.getUserId(sessionCode);
+
+        return userId;
+    }
+
+    /**
+     * API for getting devices according to authorized user
+     * 
+     * @param userId
+     *            identifier of authorized user
+     * @return ArrayList<String> - list of devices
+     */
+    public ArrayList<String> getDevices(String userId) {
+
+        ArrayList<String> deviceList = new ArrayList<String>();
+
+        deviceList = mongoDB.getDevices(userId);
+
+        return deviceList;
+    }
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/MongoDB.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/MongoDB.java
new file mode 100644 (file)
index 0000000..4f6ad4a
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.db;
+
+import java.util.ArrayList;
+
+import org.bson.Document;
+import org.iotivity.cloud.accountserver.Const;
+import org.iotivity.cloud.util.Logger;
+
+import com.mongodb.MongoClient;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoCursor;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.model.Filters;
+
+/**
+ *
+ * This class provides a set of APIs to use MongoDB APIs.
+ *
+ */
+public class MongoDB {
+
+    private MongoClient   mongoClient = null;
+    private MongoDatabase db          = null;
+
+    /**
+     * API creating MongoClient and initializing MongoDatabase
+     * 
+     * @param dbname
+     *            database name to create MongoDatabase
+     * @throws Exception
+     */
+    public MongoDB(String dbname) throws Exception {
+        mongoClient = new MongoClient();
+        mongoClient.dropDatabase(dbname);
+        db = mongoClient.getDatabase(dbname);
+    }
+
+    /**
+     * API creating collection
+     * 
+     * @param tableName
+     *            collection name
+     */
+    public void createTable(String tableName) {
+        db.createCollection(tableName);
+    }
+
+    /**
+     * API deleting collection
+     * 
+     * @param tableName
+     *            collection name
+     */
+    public void deleteTable(String tableName) {
+        db.getCollection(tableName).drop();
+    }
+
+    public MongoDatabase getMongoDatabase() {
+        return db;
+    }
+
+    /**
+     * API for storing information of authorized users
+     * 
+     * @param accountInfo
+     *            information of authorized users
+     * @param tablename
+     *            table name of mongoDB
+     */
+    public void createResource(UserSession userSession) {
+
+        Document doc = createDocument(userSession);
+        MongoCollection<Document> collection = db
+                .getCollection(Const.SESSION_TABLE);
+
+        if (collection.findOneAndReplace(Filters.and(
+                Filters.eq(Const.USER_ID, doc.get(Const.USER_ID)),
+                Filters.eq(Const.SESSION_CODE, doc.get(Const.SESSION_CODE))),
+                doc) == null) {
+
+            collection.insertOne(doc);
+        }
+
+        return;
+    }
+
+    public void createResource(UserDevice userDevice) {
+
+        Document doc = createDocument(userDevice);
+        MongoCollection<Document> collection = db
+                .getCollection(Const.DEVICE_TABLE);
+
+        if (collection.findOneAndReplace(
+                Filters.and(Filters.eq(Const.USER_ID, doc.get(Const.USER_ID)),
+                        Filters.eq(Const.DEVICE_ID, doc.get(Const.DEVICE_ID))),
+                doc) == null) {
+
+            collection.insertOne(doc);
+        }
+
+        return;
+    }
+
+    private Document createDocument(UserSession userSession) {
+
+        Document doc = new Document(Const.USER_ID, userSession.getUserId())
+                .append(Const.SESSION_CODE, userSession.getSessionCode());
+
+        return doc;
+    }
+
+    private Document createDocument(UserDevice userDevice) {
+
+        Document doc = new Document(Const.USER_ID, userDevice.getUserId())
+                .append(Const.DEVICE_ID, userDevice.getDeviceId());
+
+        return doc;
+    }
+
+    private UserSession convertSessionDocToResource(Document doc) {
+
+        UserSession userSession = new UserSession();
+
+        userSession.setUserId(doc.getString(Const.USER_ID));
+        userSession.setSessionCode(doc.getString(Const.SESSION_CODE));
+
+        return userSession;
+    }
+
+    private UserDevice convertDeviceDocToResource(Document doc) {
+
+        UserDevice userDevice = new UserDevice();
+
+        userDevice.setUserId(doc.getString(Const.USER_ID));
+        userDevice.setDeviceId(doc.getString(Const.DEVICE_ID));
+
+        return userDevice;
+    }
+
+    public String getUserId(String sessionCode) {
+
+        String userId = null;
+
+        MongoCollection<Document> collection = db
+                .getCollection(Const.SESSION_TABLE);
+
+        MongoCursor<Document> cursor = collection
+                .find(Filters.eq(Const.SESSION_CODE, sessionCode)).iterator();
+
+        try {
+
+            while (cursor.hasNext()) {
+
+                Document doc = cursor.next();
+                UserSession userSession = convertSessionDocToResource(doc);
+
+                userId = userSession.getUserId();
+                break;
+            }
+
+        } finally {
+
+            cursor.close();
+        }
+
+        return userId;
+    }
+
+    /**
+     * API for getting devices according to user from mongoDB
+     * 
+     * @param userId
+     *            user identifier
+     * @param tablename
+     *            table name of mongoDB
+     */
+    public ArrayList<String> getDevices(String userId) {
+
+        ArrayList<String> deviceList = new ArrayList<String>();
+
+        MongoCollection<Document> collection = db
+                .getCollection(Const.DEVICE_TABLE);
+
+        MongoCursor<Document> cursor = collection
+                .find(Filters.eq(Const.USER_ID, userId)).iterator();
+
+        try {
+
+            while (cursor.hasNext()) {
+
+                Document doc = cursor.next();
+                UserDevice userDeivce = convertDeviceDocToResource(doc);
+
+                deviceList.add(userDeivce.getDeviceId());
+            }
+
+        } finally {
+
+            cursor.close();
+        }
+
+        return deviceList;
+    }
+
+    private ArrayList<UserSession> readSessionResources() {
+
+        ArrayList<UserSession> userSessionList = new ArrayList<UserSession>();
+
+        MongoCollection<Document> collection = db
+                .getCollection(Const.SESSION_TABLE);
+        MongoCursor<Document> cursor = collection.find().iterator();
+
+        while (cursor.hasNext()) {
+
+            Document doc = cursor.next();
+            userSessionList.add(convertSessionDocToResource(doc));
+        }
+
+        cursor.close();
+
+        return userSessionList;
+    }
+
+    private ArrayList<UserDevice> readDeviceResources() {
+
+        ArrayList<UserDevice> userDeviceList = new ArrayList<UserDevice>();
+
+        MongoCollection<Document> collection = db
+                .getCollection(Const.DEVICE_TABLE);
+        MongoCursor<Document> cursor = collection.find().iterator();
+
+        while (cursor.hasNext()) {
+
+            Document doc = cursor.next();
+            userDeviceList.add(convertDeviceDocToResource(doc));
+        }
+
+        cursor.close();
+
+        return userDeviceList;
+    }
+
+    public void printResources() {
+
+        ArrayList<UserDevice> dlist = readDeviceResources();
+        int size = dlist.size();
+
+        Logger.i("*Table: " + Const.DEVICE_TABLE);
+        for (int i = 0; i < size; i++) {
+
+            UserDevice item = dlist.get(i);
+
+            Logger.i("[" + i + "]" + item.getUserId() + ", "
+                    + item.getDeviceId());
+        }
+
+        ArrayList<UserSession> slist = readSessionResources();
+        size = slist.size();
+
+        Logger.i("*Table: " + Const.SESSION_TABLE);
+
+        for (int i = 0; i < size; i++) {
+
+            UserSession item = slist.get(i);
+
+            Logger.i("[" + i + "]" + item.getUserId() + ", "
+                    + item.getSessionCode());
+
+        }
+    }
+
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/UserDevice.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/UserDevice.java
new file mode 100644 (file)
index 0000000..b0cc3c6
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.db;
+
+/**
+ *
+ * This class provides a set of APIs storing device information of authorized
+ * user.
+ *
+ */
+public class UserDevice {
+
+    private String userId   = null;
+    private String deviceId = null;
+
+    public void setUserId(String id) {
+        this.userId = id;
+    }
+
+    public void setDeviceId(String id) {
+        this.deviceId = id;
+    }
+
+    public String getUserId() {
+        return this.userId;
+    }
+
+    public String getDeviceId() {
+        return this.deviceId;
+    }
+}
\ No newline at end of file
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/UserSession.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/db/UserSession.java
new file mode 100644 (file)
index 0000000..f254dcc
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.db;
+
+/**
+ *
+ * This class provides a set of APIs storing session information of authorized
+ * user.
+ *
+ */
+public class UserSession {
+
+    private String userId      = null;
+    private String sessionCode = null;
+
+    public void setUserId(String id) {
+        this.userId = id;
+    }
+
+    public void setSessionCode(String code) {
+        this.sessionCode = code;
+    }
+
+    public String getUserId() {
+        return this.userId;
+    }
+
+    public String getSessionCode() {
+        return this.sessionCode;
+    }
+}
\ No newline at end of file
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/oauth/GitHub.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/oauth/GitHub.java
new file mode 100644 (file)
index 0000000..19b5ab6
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.oauth;
+
+import org.apache.oltu.oauth2.client.OAuthClient;
+import org.apache.oltu.oauth2.client.URLConnectionClient;
+import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest;
+import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
+import org.apache.oltu.oauth2.client.response.GitHubTokenResponse;
+import org.apache.oltu.oauth2.client.response.OAuthResourceResponse;
+import org.apache.oltu.oauth2.common.OAuth;
+import org.apache.oltu.oauth2.common.OAuthProviderType;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.iotivity.cloud.accountserver.util.JSONUtil;
+import org.iotivity.cloud.util.Logger;
+
+/**
+ *
+ * This class provides APIs relating authorization for GitHub.
+ *
+ */
+public class GitHub extends OAuthServer {
+
+    final static private String client_id    = "ea9c18f540323b0213d0";
+    final static private String secret       = "4bc0cd9fe21269507eb8eba3a32664a0f598dbc9";
+    final static private String resource_url = "https://api.github.com/user";
+
+    @Override
+    public String requestAccessToken(String authCode) {
+
+        String accessToken = null;
+
+        try {
+
+            OAuthClientRequest request = OAuthClientRequest
+                    .tokenProvider(OAuthProviderType.GITHUB)
+                    .setGrantType(GrantType.AUTHORIZATION_CODE)
+                    .setClientId(client_id).setClientSecret(secret)
+                    .setCode(authCode).buildBodyMessage();
+
+            OAuthClient oAuthClient = new OAuthClient(
+                    new URLConnectionClient());
+            GitHubTokenResponse oAuthResponse = oAuthClient.accessToken(request,
+                    GitHubTokenResponse.class);
+
+            accessToken = oAuthResponse.getAccessToken();
+
+        } catch (OAuthSystemException | OAuthProblemException e) {
+            e.printStackTrace();
+        }
+
+        return accessToken;
+    }
+
+    @Override
+    public String requestGetUserInfo(String accessToken) {
+
+        String userInfo = "{}";
+
+        try {
+
+            OAuthClientRequest request = new OAuthBearerClientRequest(
+                    resource_url).setAccessToken(accessToken)
+                            .buildQueryMessage();
+
+            OAuthClient oAuthClient = new OAuthClient(
+                    new URLConnectionClient());
+            OAuthResourceResponse resourceResponse = oAuthClient.resource(
+                    request, OAuth.HttpMethod.GET, OAuthResourceResponse.class);
+
+            userInfo = resourceResponse.getBody();
+            Logger.d("userInfo: " + userInfo);
+
+        } catch (OAuthSystemException | OAuthProblemException e) {
+            e.printStackTrace();
+        }
+
+        JSONUtil util = new JSONUtil();
+        String userIdKey = "login";
+        String userId = util.parseJSON(userInfo, userIdKey);
+
+        return userId;
+    }
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/oauth/OAuthServer.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/oauth/OAuthServer.java
new file mode 100644 (file)
index 0000000..a6f3efc
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.oauth;
+
+/**
+ *
+ * This class provides abstraction of APIs relating authorization for OAuth 2.0
+ *
+ */
+public abstract class OAuthServer {
+
+    /**
+     * API for requesting access token
+     * 
+     * @param authCode
+     *            authorization code
+     * @return access token
+     */
+    public abstract String requestAccessToken(String authCode);
+
+    /**
+     * API for getting user's information
+     * 
+     * @param accessToken
+     *            access token
+     * @return String - user information of json type
+     */
+    public abstract String requestGetUserInfo(String accessToken);
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/AccountResource.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/AccountResource.java
new file mode 100644 (file)
index 0000000..5936d24
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.resources;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.iotivity.cloud.accountserver.AccountServerManager;
+import org.iotivity.cloud.accountserver.Const;
+import org.iotivity.cloud.accountserver.util.CoapMessageBuilder;
+import org.iotivity.cloud.accountserver.util.JSONUtil;
+import org.iotivity.cloud.base.Resource;
+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.base.protocols.coap.enums.CoapStatus;
+import org.iotivity.cloud.util.Logger;
+
+import io.netty.channel.ChannelHandlerContext;
+
+/**
+ *
+ * This class provides a set of APIs to handle requests for publishing and
+ * finding resources.
+ *
+ */
+public class AccountResource extends Resource {
+
+    public AccountResource() {
+        setUri(Const.ACCOUNT_URI);
+    }
+
+    @Override
+    public void onRequestReceived(ChannelHandlerContext ctx,
+            CoapRequest request) {
+
+        Logger.d("AccountResource IN");
+
+        if (ctx == null || request == null) {
+            Logger.d("ctx or request msg is null");
+        }
+
+        else {
+            CoapMethod method = request.getRequestMethod();
+
+            switch (method) {
+                case GET:
+                    try {
+                        handleGetRequest(ctx, request);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    break;
+
+                case POST:
+                    try {
+                        handlePostRequest(ctx, request);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    break;
+
+                default:
+                    Logger.w("method[" + method + "] is not supported");
+                    break;
+            }
+        }
+    }
+
+    /**
+     * API for handling GET message
+     * 
+     * @param ctx
+     *            ChannelHandlerContext of request message
+     * @param request
+     *            CoAP request message
+     * @throws Exception
+     */
+    private void handleGetRequest(ChannelHandlerContext ctx,
+            CoapRequest request) throws Exception {
+
+        String reqType = extractQuery(request, Const.REQ_TYPE);
+
+        if (reqType == null)
+            throw new IllegalArgumentException(
+                    "request type is null in query!");
+
+        CoapResponse response = null;
+
+        switch (reqType) {
+
+            case Const.TYPE_FIND:
+                response = handleFindRequest(request);
+                break;
+            default:
+                Logger.w("reqType[" + reqType + "] is not supported");
+        }
+
+        ctx.write(response);
+
+    }
+
+    /**
+     * API for handling POST message
+     * 
+     * @param ctx
+     *            ChannelHandlerContext of request message
+     * @param request
+     *            CoAP request message
+     * @throws Exception
+     */
+    private void handlePostRequest(ChannelHandlerContext ctx,
+            CoapRequest request) throws Exception {
+
+        String reqType = extractQuery(request, Const.REQ_TYPE);
+
+        if (reqType == null)
+            throw new IllegalArgumentException(
+                    "request type is null in query!");
+
+        CoapResponse response = null;
+
+        switch (reqType) {
+            case Const.TYPE_PUBLISH:
+                response = handlePublishRequest(request);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "request type is not supported");
+        }
+
+        ctx.write(response);
+    }
+
+    private CoapResponse handlePublishRequest(CoapRequest request) {
+
+        String payload = request.getPayloadString();
+
+        JSONUtil util = new JSONUtil();
+        String userId = util.parseJSON(payload, Const.REQUEST_USER_ID);
+        String deviceId = util.parseJSON(payload, Const.REQUEST_DEVICE_ID);
+
+        Logger.d("userId: " + userId + ", deviceId: " + deviceId);
+
+        AccountServerManager oauthServerManager = new AccountServerManager();
+        Boolean status = oauthServerManager.registerUserAccount(userId,
+                deviceId);
+
+        Logger.d("status : " + status);
+
+        CoapMessageBuilder responseMessage = new CoapMessageBuilder();
+        CoapResponse coapResponse = null;
+
+        if (status) {
+            coapResponse = responseMessage.buildCoapResponse(request.getToken(),
+                    CoapStatus.CREATED);
+        } else {
+            coapResponse = responseMessage.buildCoapResponse(request.getToken(),
+                    CoapStatus.INTERNAL_SERVER_ERROR);
+        }
+
+        return coapResponse;
+    }
+
+    private CoapResponse handleFindRequest(CoapRequest request) {
+
+        String payload = request.getPayloadString();
+        // String payload = getPayloadString(request.getPayload());
+
+        JSONUtil util = new JSONUtil();
+        String userId = util.parseJSON(payload, Const.REQUEST_USER_ID);
+
+        Logger.d("userId: " + userId);
+
+        AccountServerManager oauthServerManager = new AccountServerManager();
+        ArrayList<String> deviceList = oauthServerManager
+                .requestAccountDevices(userId);
+
+        ResponseObject response = new ResponseObject();
+        response.setDeviceList(deviceList);
+
+        String responseJson = convertFindResponseToJson(response);
+        Logger.d("responseJson: " + responseJson);
+
+        CoapMessageBuilder responseMessage = new CoapMessageBuilder();
+        CoapResponse coapResponse = responseMessage.buildCoapResponse(
+                request.getToken(), responseJson, CoapStatus.CONTENT);
+
+        return coapResponse;
+    }
+
+    private String convertFindResponseToJson(ResponseObject response) {
+
+        HashMap<Object, Object> responseMap = new HashMap<Object, Object>();
+
+        ArrayList<String> deviceList = response.getDeviceList();
+        responseMap.put(Const.RESPONSE_DEVICES, deviceList);
+
+        JSONUtil jsonUtil = new JSONUtil();
+        String responseJson = jsonUtil.writeJSON(responseMap);
+
+        return responseJson;
+    }
+
+    private String extractQuery(CoapRequest request, String key) {
+
+        String value = null;
+
+        List<String> Segments = request.getUriQuerySegments();
+
+        for (String s : Segments) {
+
+            String pair[] = s.split("=");
+
+            if (pair[0].equals(key)) {
+
+                value = pair[1];
+            }
+        }
+
+        return value;
+    }
+
+    /*
+     * private static String getPayloadString(byte[] payload) {
+     * 
+     * if (payload == null) return "";
+     * 
+     * return new String(payload, Charset.forName("UTF-8")); }
+     */
+
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/AuthResource.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/AuthResource.java
new file mode 100644 (file)
index 0000000..234eaf3
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.resources;
+
+import java.util.HashMap;
+import java.util.List;
+
+import org.iotivity.cloud.accountserver.AccountServerManager;
+import org.iotivity.cloud.accountserver.Const;
+import org.iotivity.cloud.accountserver.util.CoapMessageBuilder;
+import org.iotivity.cloud.accountserver.util.JSONUtil;
+import org.iotivity.cloud.base.Resource;
+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.base.protocols.coap.enums.CoapStatus;
+import org.iotivity.cloud.util.Logger;
+
+import io.netty.channel.ChannelHandlerContext;
+
+/**
+ *
+ * This class provides a set of APIs to register account information of
+ * authorized user.
+ *
+ */
+public class AuthResource extends Resource {
+
+    public AuthResource() {
+        setUri(Const.AUTH_URI);
+    }
+
+    @Override
+    public void onRequestReceived(ChannelHandlerContext ctx, CoapRequest request) {
+
+        Logger.d("AuthResource IN");
+
+        if (ctx == null || request == null) {
+            Logger.d("ctx or request msg is null");
+        }
+
+        else {
+            CoapMethod method = request.getRequestMethod();
+
+            switch (method) {
+                case POST:
+                    try {
+                        handlePostRequest(ctx, request);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    break;
+
+                default:
+                    Logger.w("method(" + method + ") is not supported");
+                    break;
+            }
+        }
+    }
+
+    /**
+     * API for handling POST message
+     * 
+     * @param ctx
+     *            ChannelHandlerContext of request message
+     * @param request
+     *            CoAP request message
+     * @throws Exception
+     */
+    private void handlePostRequest(ChannelHandlerContext ctx,
+            CoapRequest request) throws Exception {
+
+        String reqType = extractQuery(request, Const.REQ_TYPE);
+
+        if (reqType == null)
+            throw new IllegalArgumentException("request type is null in query!");
+
+        CoapResponse response = null;
+
+        switch (reqType) {
+            case Const.TYPE_REGISTER:
+                response = handleRegisterRequest(request);
+                break;
+            case Const.TYPE_LOGIN:
+                response = handleLoginRequest(request);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "request type is not supported");
+        }
+
+        ctx.write(response);
+    }
+
+    private CoapResponse handleLoginRequest(CoapRequest request) {
+
+        String payload = request.getPayloadString();
+
+        JSONUtil util = new JSONUtil();
+        String sessionCode = util
+                .parseJSON(payload, Const.REQUEST_SESSION_CODE);
+
+        Logger.d("sessionCode: " + sessionCode);
+
+        AccountServerManager oauthServerManager = new AccountServerManager();
+        String userId = oauthServerManager.requestUserId(sessionCode);
+        Logger.d("userId: " + userId);
+
+        CoapMessageBuilder responseMessage = new CoapMessageBuilder();
+        CoapResponse coapResponse = null;
+
+        if (userId != null) {
+
+            ResponseObject response = new ResponseObject();
+            response.setUserId(userId);
+
+            String responseJson = convertLoginResponseToJson(response);
+            Logger.d("responseJson: " + responseJson);
+
+            coapResponse = responseMessage.buildCoapResponse(
+                    request.getToken(), responseJson, CoapStatus.CREATED);
+
+        } else {
+
+            coapResponse = responseMessage.buildCoapResponse(
+                    request.getToken(), CoapStatus.INTERNAL_SERVER_ERROR);
+
+        }
+
+        return coapResponse;
+    }
+
+    private CoapResponse handleRegisterRequest(CoapRequest request) {
+
+        String payload = request.getPayloadString();
+
+        JSONUtil util = new JSONUtil();
+        String authCode = util.parseJSON(payload, Const.REQUEST_AUTH_CODE);
+        String authServer = util.parseJSON(payload, Const.REQUEST_AUTH_SERVER);
+
+        Logger.d("authCode: " + authCode + ", authServer: " + authServer);
+
+        AccountServerManager oauthServerManager = new AccountServerManager();
+
+        String userId = oauthServerManager.requestUserId(authCode, authServer);
+        String sessionCode = oauthServerManager.registerUserAccount(userId);
+
+        Logger.d("userId: " + userId + ", sessionCode: " + sessionCode);
+
+        CoapMessageBuilder responseMessage = new CoapMessageBuilder();
+        CoapResponse coapResponse = null;
+
+        if (userId != null && sessionCode != null) {
+
+            ResponseObject response = new ResponseObject();
+            response.setSessionCode(sessionCode);
+            response.setUserId(userId);
+
+            String responseJson = convertRegisterResponseToJson(response);
+            Logger.d("responseJson: " + responseJson);
+
+            coapResponse = responseMessage.buildCoapResponse(
+                    request.getToken(), responseJson, CoapStatus.CREATED);
+
+        } else {
+
+            coapResponse = responseMessage.buildCoapResponse(
+                    request.getToken(), CoapStatus.UNAUTHORIZED);
+
+        }
+
+        return coapResponse;
+    }
+
+    private String convertRegisterResponseToJson(ResponseObject response) {
+
+        HashMap<Object, Object> responseMap = new HashMap<Object, Object>();
+
+        String sessionCode = response.getSessionCode();
+        String userId = response.getUserId();
+
+        if (userId != null)
+            responseMap.put(Const.RESPONSE_USER_ID, userId);
+
+        if (sessionCode != null)
+            responseMap.put(Const.RESPONSE_SESSION_CODE, sessionCode);
+
+        JSONUtil jsonUtil = new JSONUtil();
+        String responseJson = jsonUtil.writeJSON(responseMap);
+
+        return responseJson;
+    }
+
+    private String convertLoginResponseToJson(ResponseObject response) {
+
+        HashMap<Object, Object> responseMap = new HashMap<Object, Object>();
+
+        String userId = response.getUserId();
+
+        if (userId != null)
+            responseMap.put(Const.RESPONSE_USER_ID, userId);
+
+        JSONUtil jsonUtil = new JSONUtil();
+        String responseJson = jsonUtil.writeJSON(responseMap);
+
+        return responseJson;
+    }
+
+    private String extractQuery(CoapRequest request, String key) {
+
+        String value = null;
+
+        List<String> Segments = request.getUriQuerySegments();
+
+        for (String s : Segments) {
+
+            String pair[] = s.split("=");
+
+            if (pair[0].equals(key)) {
+
+                value = pair[1];
+            }
+        }
+
+        return value;
+    }
+
+    /*
+     * private static String getPayloadString(byte[] payload) {
+     * 
+     * if (payload == null) return "";
+     * 
+     * return new String(payload, Charset.forName("UTF-8")); }
+     */
+
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/ResponseObject.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/ResponseObject.java
new file mode 100644 (file)
index 0000000..4a506e8
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.resources;
+
+import java.util.ArrayList;
+
+/**
+ * 
+ * This class provides a set of APIs to manage data for response according to
+ * request.
+ * 
+ */
+public class ResponseObject {
+    // private String channel = null;
+    private String            sessionCode = null;
+    private String            userId      = null;
+    private ArrayList<String> deviceList  = null;
+
+    ResponseObject() {
+        deviceList = new ArrayList<String>();
+    }
+
+    public String getUserId() {
+        return this.userId;
+    }
+
+    public void setUserId(String id) {
+        this.userId = id;
+    }
+
+    public String getSessionCode() {
+        return this.sessionCode;
+    }
+
+    public void setSessionCode(String code) {
+        this.sessionCode = code;
+    }
+
+    public void setDeviceList(ArrayList<String> list) {
+        this.deviceList = list;
+    }
+
+    public ArrayList<String> getDeviceList() {
+        return this.deviceList;
+    }
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/util/CoapMessageBuilder.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/util/CoapMessageBuilder.java
new file mode 100644 (file)
index 0000000..47e9269
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.util;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+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.base.protocols.coap.enums.CoapOption;
+import org.iotivity.cloud.base.protocols.coap.enums.CoapStatus;
+
+/**
+ * 
+ * This class provides utility for making CoAP request and response.
+ * 
+ */
+public class CoapMessageBuilder {
+
+    public static final int APPLICATION_JSON = 50;
+
+    public CoapResponse buildCoapResponse(byte[] token, CoapStatus status) {
+
+        return buildCoapResponse(token, null, status);
+    }
+
+    public CoapResponse buildCoapResponse(byte[] token, String jsonString,
+            CoapStatus status) {
+
+        CoapResponse coapResponse = new CoapResponse(status);
+
+        coapResponse.setToken(token);
+
+        byte[] bytes = ByteBuffer.allocate(4)
+                .putInt(CoapMessageBuilder.APPLICATION_JSON).array();
+        coapResponse.addOption(CoapOption.CONTENT_FORMAT.getvalue(), bytes);
+
+        if (jsonString != null)
+            coapResponse
+                    .setPayload(jsonString.getBytes(StandardCharsets.UTF_8));
+
+        return coapResponse;
+    }
+
+    public CoapRequest buildCoapRequest(byte[] token, String jsonString) {
+
+        CoapRequest coapRequest = new CoapRequest(CoapMethod.GET);
+
+        coapRequest.setToken(token);
+
+        byte[] bytes = ByteBuffer.allocate(4)
+                .putInt(CoapMessageBuilder.APPLICATION_JSON).array();
+        coapRequest.addOption(CoapOption.CONTENT_FORMAT.getvalue(), bytes);
+
+        coapRequest.setPayload(jsonString.getBytes(StandardCharsets.UTF_8));
+
+        return coapRequest;
+    }
+
+    /*
+     * 
+     * public String getJsonAuthServerResponse() {
+     * 
+     * return "{ \"" + OAuthConstant.AUTH_SERVER + "\" : \"" +
+     * OAuthConstant.AUTH_SERVER_GITHUB + "\" }"; }
+     * 
+     * public String getJsonAuthInfoResponse() {
+     * 
+     * return "\n{\n" + " \"" + OAuthConstant.AUTH_ADDRESS + "\" : \"" +
+     * OAuthConstant.GITHUB_ADDRESS + "\",\n" + " \"" +
+     * OAuthConstant.AUTH_RESPONSE_TYPE + "\" : \"" +
+     * OAuthConstant.AUTH_CODE_VALUE + "\",\n" + " \"" +
+     * OAuthConstant.AUTH_CLIENT_ID + "\" : \"" + OAuthConstant.GITHUB_CLIENT_ID
+     * + "\",\n" + " \"" + OAuthConstant.AUTH_REDIRECT_URI + "\" : \"" +
+     * OAuthConstant.GITHUB_REDIRECT_URL + "\"" + "\n}"; }
+     * 
+     * public String getJsonAuthQueryRequest(String auth_server, String
+     * auth_code, String auth_di) {
+     * 
+     * return "\n{\n" + " \"" + OAuthConstant.AUTH_TYPE + "\" : \"" +
+     * OAuthConstant.AUTH_TYPE_QUERY + "\",\n" + " \"" +
+     * OAuthConstant.AUTH_SERVER + "\" : \"" + auth_server + "\",\n" + " \"" +
+     * OAuthConstant.AUTH_CODE + "\" : \"" + auth_code + "\",\n" + " \"" +
+     * OAuthConstant.AUTH_DEVICE_ID + "\" : \"" + auth_di + "\"" + "\n}"; }
+     */
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/util/JSONUtil.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/util/JSONUtil.java
new file mode 100644 (file)
index 0000000..70fca30
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.accountserver.util;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * 
+ * This class provides utility for parsing JSON object and converting data to
+ * JSON string.
+ * 
+ */
+public class JSONUtil {
+
+    private static ObjectMapper mapper = new ObjectMapper();
+
+    public String parseJSON(String jsonString, String key) {
+
+        if (jsonString == null || jsonString.equals(""))
+            return null;
+
+        String value = null;
+
+        try {
+            @SuppressWarnings("unchecked")
+            Map<String, String> jsonMap = mapper.readValue(jsonString,
+                    Map.class);
+            value = jsonMap.get(key);
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+
+        return value;
+    }
+
+    public String writeJSON(HashMap<Object, Object> data) {
+        if (data == null)
+            return null;
+
+        String json = null;
+        try {
+            json = mapper.writeValueAsString(data);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+
+        if (json == null)
+            json = "{}";
+
+        return json;
+    }
+}
diff --git a/cloud/account/src/test/java/org/iotivity/cloud/testaccountserver/TestAccountServer.java b/cloud/account/src/test/java/org/iotivity/cloud/testaccountserver/TestAccountServer.java
new file mode 100644 (file)
index 0000000..9080ceb
--- /dev/null
@@ -0,0 +1,169 @@
+package org.iotivity.cloud.testaccountserver;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Test;
+import org.iotivity.cloud.accountserver.Const;
+import org.iotivity.cloud.accountserver.resources.AccountResource;
+import org.iotivity.cloud.accountserver.resources.AuthResource;
+import org.iotivity.cloud.accountserver.util.JSONUtil;
+import org.iotivity.cloud.base.CoapClient;
+import org.iotivity.cloud.base.CoapServer;
+import org.iotivity.cloud.base.ResourceManager;
+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;
+
+public class TestAccountServer {
+
+    private AuthResource    authResource    = new AuthResource();
+    private AccountResource accountResource = new AccountResource();
+
+    private CoapServer      coapServer      = null;
+    private CoapClient      coapClient      = null;
+    private static String   sessionCode     = null;
+
+    static class CoapClientHandler extends
+            SimpleChannelInboundHandler<CoapResponse> {
+
+        ChannelHandlerContext connectCtx = null;
+
+        @Override
+        public void channelActive(ChannelHandlerContext ctx) throws Exception {
+            connectCtx = ctx;
+        }
+
+        @Override
+        protected void channelRead0(ChannelHandlerContext arg0,
+                CoapResponse arg1) throws Exception {
+
+            if (arg1.getTokenString().equals("1111")) {
+
+                String json = arg1.getPayloadString();
+                JSONUtil util = new JSONUtil();
+
+                sessionCode = util.parseJSON(json, "session");
+            }
+
+        }
+    }
+
+    public void startServer() throws Exception {
+
+        coapServer = new CoapServer();
+
+        ResourceManager resourceManager = new ResourceManager();
+        coapServer.addHandler(resourceManager);
+
+        resourceManager.registerResource(new AuthResource());
+        resourceManager.registerResource(new AccountResource());
+
+        coapServer.startServer(new InetSocketAddress(5685));
+    }
+
+    public ChannelHandlerContext startClient() throws Exception {
+
+        coapClient = new CoapClient();
+
+        CoapClientHandler coapHandler = new CoapClientHandler();
+        coapClient.addHandler(coapHandler);
+
+        coapClient.startClient(new InetSocketAddress("127.0.0.1", 5685));
+
+        return coapHandler.connectCtx;
+    }
+
+    @Test
+    public void testHandleRegisterRequest() throws Exception {
+
+        System.out.println("Write your authCode before test by following url.");
+        System.out
+                .println("https://github.com/login?return_to=%2Flogin%2Foauth%2Fauthorize%3Fclient_id%3Dea9c18f540323b0213d0%26redirect_uri%3Dhttp%253A%252F%252Fwww.example.com%252Foauth_callback%252F");
+
+        String authCode = "a05c2d8f6531ec15230e"; // write your authCode here.
+        String authServer = "github";
+
+        String json = "{\"authcode\":\"" + authCode + "\",\"authprovider\":\""
+                + authServer + "\"}";
+
+        CoapRequest request = new CoapRequest(CoapMethod.POST);
+        request.setUriPath(Const.AUTH_URI);
+        request.setUriQuery("reqtype=register");
+        request.setToken("1111".getBytes(StandardCharsets.UTF_8));
+        request.setPayload(json.getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+        authResource.onRequestReceived(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testHandlerLoginReqeust() throws Exception {
+
+        String json = "{\"session\":\"" + sessionCode + "\"}";
+
+        CoapRequest request = new CoapRequest(CoapMethod.POST);
+        request.setUriPath(Const.AUTH_URI);
+        request.setUriQuery("reqtype=login");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+        request.setPayload(json.getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+        authResource.onRequestReceived(ctx, request);
+
+        coapClient.sendRequest(request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testHandlerPublishReqeust() throws Exception {
+
+        String userId = "eyedglen";
+        String deviceId = "d0001";
+        String json = "{\"userid\":\"" + userId + "\",\"deviceId\":\""
+                + deviceId + "\"}";
+
+        CoapRequest request = new CoapRequest(CoapMethod.POST);
+        request.setUriPath(Const.ACCOUNT_URI);
+        request.setUriQuery("reqtype=publish");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+        request.setPayload(json.getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+        accountResource.onRequestReceived(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testHandlerFindReqeust() throws Exception {
+
+        String userId = "eyedglen";
+        String json = "{\"userid\":\"" + userId + "\"}";
+
+        CoapRequest request = new CoapRequest(CoapMethod.POST);
+        request.setUriPath(Const.ACCOUNT_URI);
+        request.setUriQuery("reqtype=find");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+        request.setPayload(json.getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+        accountResource.onRequestReceived(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+}
diff --git a/cloud/interface/.classpath b/cloud/interface/.classpath
new file mode 100644 (file)
index 0000000..f619a53
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="target/classes" path="src/main/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/cloud/interface/.gitignore b/cloud/interface/.gitignore
new file mode 100644 (file)
index 0000000..b83d222
--- /dev/null
@@ -0,0 +1 @@
+/target/
diff --git a/cloud/interface/.project b/cloud/interface/.project
new file mode 100644 (file)
index 0000000..92dcbdb
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>CloudInterface</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.m2e.core.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.m2e.core.maven2Nature</nature>
+       </natures>
+</projectDescription>
diff --git a/cloud/interface/README b/cloud/interface/README
new file mode 100644 (file)
index 0000000..c0867c7
--- /dev/null
@@ -0,0 +1,26 @@
+This project contains the Cloud Interface(CI) Server code.
+
+Build and Run
+
+1) Install Apache Maven if you don't have it
+
+       http://maven.apache.org
+
+2) Build a CloudStack. If you are building first time, then build the stack.
+
+       go to "stack" folder in root directory
+       $ mvn install
+
+3) Build a .jar file
+
+       $ mvn install
+
+       - The CloudInterface-0.0.1-SNAPSHOT.jar file will be placed in the "target" folder
+
+4) Run .jar file
+
+       go to "target" folder
+       $ java -jar CloudInterface-0.0.1-SNAPSHOT.jar arg1(CI CoAP Server Port) arg2(RD CoAP Server IP) arg3(RD CoAP Server Port) arg4(Account Server IP) arg5(Account Server Port)
+       e.g. java -jar CloudInterface-0.0.1-SNAPSHOT.jar 5683 127.0.0.1 5684 127.0.0.1 5685
+
+       - Before running a CI server, you should run a RD server and a Acccount server first.
diff --git a/cloud/interface/pom.xml b/cloud/interface/pom.xml
new file mode 100644 (file)
index 0000000..3c29dfd
--- /dev/null
@@ -0,0 +1,64 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.iotivity.cloud</groupId>
+  <artifactId>CloudInterface</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  
+  <properties>
+               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+       </properties>
+       
+  <dependencies>
+               <dependency>
+                       <groupId>org.iotivity.cloud</groupId>
+                       <artifactId>CloudStack</artifactId>
+                       <version>0.0.1-SNAPSHOT</version>
+               </dependency>   
+       </dependencies>
+       
+  <build>
+               <plugins>
+                       <plugin>
+                               <inherited>true</inherited>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <configuration>
+                                       <source>1.7</source>
+                                       <target>1.7</target>
+                                       <encoding>UTF-8</encoding>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-jar-plugin</artifactId>
+                               <configuration>
+                                       <archive>
+                                               <manifest>
+                                                       <mainClass>org.iotivity.cloud.ciserver.CloudInterfaceServer</mainClass>
+                                                       <addClasspath>true</addClasspath>
+                                                       <classpathPrefix>lib/</classpathPrefix>
+                                               </manifest>
+                                       </archive>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-dependency-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                               <id>copy-dependencies</id>
+                                               <phase>package</phase>
+                                               <goals>
+                                                       <goal>copy-dependencies</goal>
+                                               </goals>
+                                       </execution>
+                               </executions>
+                               <configuration>
+                                       <outputDirectory>target/lib</outputDirectory>
+                                       <overWriteIfNewer>true</overWriteIfNewer>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+  
+</project>
\ No newline at end of file
diff --git a/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/CloudInterfaceServer.java b/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/CloudInterfaceServer.java
new file mode 100644 (file)
index 0000000..83301fa
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.ciserver;
+
+import java.net.InetSocketAddress;
+
+import org.iotivity.cloud.base.CoapServer;
+import org.iotivity.cloud.base.ResourceManager;
+import org.iotivity.cloud.base.SessionManager;
+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.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(
+                    "coap server port and RDServer_Address port AccountServer_Address Port required\n"
+                            + "ex) 5683 127.0.0.1 5684 127.0.0.1 5685\n");
+            return;
+        }
+
+        ResourceManager resourceManager = null;
+        SessionManager sessionManager = null;
+        CoapServer coapServer = null;
+
+        coapServer = new CoapServer();
+
+        sessionManager = new SessionManager();
+
+        resourceManager = new ResourceManager(sessionManager);
+
+        coapServer.addHandler(
+                new CoapAuthHandler(args[3], Integer.parseInt(args[4])));
+
+        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])));
+
+        coapServer.addHandler(resourceManager);
+
+        resourceManager.registerResource(new KeepAliveResource(sessionManager,
+                new int[] { 1, 2, 4, 8 }));
+
+        coapServer
+                .startServer(new InetSocketAddress(Integer.parseInt(args[0])));
+    }
+}
diff --git a/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/Constants.java b/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/Constants.java
new file mode 100644 (file)
index 0000000..918fab8
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.ciserver;
+
+import io.netty.util.AttributeKey;
+
+public class Constants {
+    public static final String RD_URI         = "oic/rd";   // resource
+                                                            // publish uri
+    public static final String KEEP_ALIVE_URI = "oic/ping"; // keepalive
+                                                            // resource uri
+    public static final String WELL_KNOWN_URI = "oic/res";  // resource
+                                                            // discover uri
+
+    public static final String DEVICE_LIST = "st=didList"; // oauth device
+                                                           // list riquery
+
+    public static final String AUTH_URI    = "oic/auth";
+    public static final String ACCOUNT_URI = "oic/account";
+
+    public static final AttributeKey<String> Attribute_UserId = AttributeKey
+            .newInstance("userId");
+}
diff --git a/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/protocols/CoapAuthHandler.java b/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/protocols/CoapAuthHandler.java
new file mode 100644 (file)
index 0000000..d0daaaa
--- /dev/null
@@ -0,0 +1,122 @@
+package org.iotivity.cloud.ciserver.protocols;
+
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.iotivity.cloud.base.CoapClient;
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+import org.iotivity.cloud.base.protocols.coap.CoapResponse;
+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.JSONUtil;
+import org.iotivity.cloud.util.Logger;
+
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandler.Sharable;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.util.AttributeKey;
+
+@Sharable
+public class CoapAuthHandler extends ChannelDuplexHandler {
+
+    private static final AttributeKey<ChannelHandlerContext> keyAuthClient = AttributeKey
+            .newInstance("authCtx");
+
+    private class AccountHandler
+            extends SimpleChannelInboundHandler<CoapResponse> {
+
+        @Override
+        public void channelRead0(ChannelHandlerContext ctx, CoapResponse msg)
+                throws Exception {
+            Logger.d("Receive response from account, forward to client");
+
+            ChannelHandlerContext ctxToDevice = ctx.channel()
+                    .attr(keyAuthClient).get();
+
+            if (msg.getResponseCode() == CoapStatus.CREATED) {
+                Map<String, String> response = JSONUtil
+                        .parseJSON(new String(msg.getPayload(), StandardCharsets.UTF_8));
+
+                String userId = response.get("userid");
+                if (userId != null) {
+                    ctxToDevice.channel().attr(Constants.Attribute_UserId)
+                            .set(userId);
+                }
+                msg.setPayload(cbor.encodingPayloadToCbor(response));
+
+                CoapAuthHandler authHandler = ctxToDevice.channel().pipeline()
+                        .get(CoapAuthHandler.class);
+
+                ctxToDevice.channel().pipeline().remove(authHandler);
+            }
+
+            ctxToDevice.writeAndFlush(msg);
+
+            if (msg.getResponseCode() != CoapStatus.CREATED)
+                ctxToDevice.close();
+        }
+
+        @Override
+        public void exceptionCaught(ChannelHandlerContext ctx,
+                Throwable cause) {
+            cause.printStackTrace();
+            ctx.close();
+        }
+    }
+
+    private CoapClient accountClient = new CoapClient();
+
+    public CoapAuthHandler(String accountAddress, int accountPort) {
+
+        accountClient.addHandler(new AccountHandler());
+        try {
+            accountClient.startClient(
+                    new InetSocketAddress(accountAddress, accountPort));
+        } catch (InterruptedException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+    private Cbor<HashMap<Object, Object>> cbor = new Cbor<HashMap<Object, Object>>();
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg)
+            throws Exception {
+
+        if (msg instanceof CoapRequest) {
+            CoapRequest request = (CoapRequest) msg;
+            switch (request.getUriPath()) {
+                // This handler only used for initial handshake
+                case Constants.AUTH_URI:
+                    HashMap<Object, Object> payloadData = cbor
+                            .parsePayloadFromCbor(request.getPayload(),
+                                    HashMap.class);
+                    request.setPayload(
+                            JSONUtil.writeJSON(payloadData).getBytes(StandardCharsets.UTF_8));
+                    accountClient.getChannelFuture().channel()
+                            .attr(keyAuthClient).set(ctx);
+                    accountClient.sendRequest(request);
+                    return;
+
+                case Constants.KEEP_ALIVE_URI:
+                    super.channelRead(ctx, msg);
+                    return;
+
+                default:
+                    CoapResponse response = new CoapResponse(
+                            CoapStatus.UNAUTHORIZED);
+                    Logger.e("Sending UNAUTHORIZED to client");
+                    ctx.writeAndFlush(response);
+                    break;
+            }
+        }
+
+        Logger.d("Invalid packet for authenticating");
+        ctx.close();
+    }
+}
diff --git a/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/protocols/CoapRelayHandler.java b/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/protocols/CoapRelayHandler.java
new file mode 100644 (file)
index 0000000..395b326
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.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;
+import org.iotivity.cloud.base.SessionManager;
+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.base.protocols.coap.enums.CoapStatus;
+import org.iotivity.cloud.ciserver.Constants;
+import org.iotivity.cloud.util.Logger;
+import org.iotivity.cloud.util.Net;
+
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandler.Sharable;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.util.AttributeKey;
+
+/**
+ *
+ * This class is relay handler relating Cloud Interface
+ *
+ */
+@Sharable
+public class CoapRelayHandler extends ChannelDuplexHandler {
+
+    /////////// Handler for Resource Directory
+    private static final AttributeKey<ChannelHandlerContext> keyRDClient = AttributeKey
+            .newInstance("rdCtx");
+
+    private static class RDHandler
+            extends SimpleChannelInboundHandler<CoapResponse> {
+        @Override
+        public void channelRead0(ChannelHandlerContext ctx, CoapResponse msg)
+                throws Exception {
+            Logger.d("Receive response from RD, forward to client");
+
+            ChannelHandlerContext ctxToDevice = ctx.channel().attr(keyRDClient)
+                    .get();
+            ctxToDevice.writeAndFlush(msg);
+        }
+
+        @Override
+        public void exceptionCaught(ChannelHandlerContext ctx,
+                Throwable cause) {
+            cause.printStackTrace();
+            ctx.close();
+        }
+    }
+
+    private CoapClient rdClient = new CoapClient();
+    ///////////
+
+    ////////// Handler for Account Server
+    private static final AttributeKey<List<CoapRequest>> keyAccountClient = AttributeKey
+            .newInstance("accountCtx");
+
+    private class AccountHandler
+            extends SimpleChannelInboundHandler<CoapResponse> {
+        @Override
+        public void channelRead0(ChannelHandlerContext ctx, CoapResponse msg)
+                throws Exception {
+            Logger.d("Receive response from AS, make request to RD");
+
+            CoapRequest rdRequest = null;
+
+            switch (msg.getResponseCode()) {
+                case CREATED:
+                    // response of POST request
+                    rdRequest = ctx.channel().attr(keyAccountClient).get()
+                            .remove(0);
+                    rdClient.sendRequest(rdRequest);
+                    break;
+
+                case CONTENT:
+                    // response of GET request, contains did list
+                    rdRequest = ctx.channel().attr(keyAccountClient).get()
+                            .remove(0);
+                    // change uri to send RD
+                    rdRequest.setUriPath(Constants.RD_URI);
+                    rdRequest.setUriQuery(Constants.DEVICE_LIST);
+                    rdRequest.setPayload(msg.getPayload());
+                    rdClient.sendRequest(rdRequest);
+                    break;
+
+                default:
+                    break;
+            }
+        }
+
+        @Override
+        public void exceptionCaught(ChannelHandlerContext ctx,
+                Throwable cause) {
+            cause.printStackTrace();
+            ctx.close();
+        }
+    }
+
+    private CoapClient asClient = new CoapClient();
+    //////////
+
+    private SessionManager sessionManager = null;
+
+    public CoapRelayHandler(SessionManager sessionManager, String rdAddress,
+            int rdPort, String acAddress, int acPort) {
+        this.sessionManager = sessionManager;
+
+        rdClient.addHandler(new RDHandler());
+
+        asClient.addHandler(new AccountHandler());
+
+        try {
+            rdClient.startClient(new InetSocketAddress(rdAddress, rdPort));
+            asClient.startClient(new InetSocketAddress(acAddress, acPort));
+        } catch (InterruptedException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        asClient.getChannelFuture().channel().attr(keyAccountClient)
+                .set(new ArrayList<CoapRequest>());
+    }
+
+    private static final AttributeKey<ChannelHandlerContext> keyDevice = AttributeKey
+            .newInstance("deviceCtx");
+
+    private HashMap<String, CoapClient> ciRelayClients = new HashMap<String, CoapClient>();
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg)
+            throws Exception {
+
+        if (msg instanceof CoapRequest) {
+            CoapRequest request = (CoapRequest) msg;
+            // Parse uri, send to RD
+            String uriPath = request.getUriPath();
+            CoapRequest accountRequest = null;
+            String userId, deviceId, authPayload;
+            CoapResponse response = null;
+
+            Logger.d("Request received, URI: " + uriPath);
+            switch (uriPath) {
+                case Constants.AUTH_URI:
+                    // This case user wants to logout
+                    if (request.getUriQuery().endsWith("logout")) {
+                        ctx.channel().attr(Constants.Attribute_UserId).remove();
+                        response = new CoapResponse(CoapStatus.DELETED);
+                    } else {
+                        response = new CoapResponse(CoapStatus.BAD_REQUEST);
+                    }
+                    ctx.writeAndFlush(response);
+                    break;
+
+                case Constants.RD_URI:
+                    // RD POST means publish device to server
+                    switch (request.getRequestMethod()) {
+                        case POST:
+                            userId = ctx.channel()
+                                    .attr(Constants.Attribute_UserId).get();
+                            deviceId = request.decodeDeviceId();
+                            authPayload = String.format(
+                                    "{\"userid\":\"%s\",\"deviceid\":\"%s\"}",
+                                    userId, deviceId);
+                            accountRequest = new CoapRequest(CoapMethod.POST);
+                            accountRequest.setUriPath(Constants.ACCOUNT_URI);
+                            accountRequest.setUriQuery("reqtype=publish");
+                            accountRequest.setToken(request.getToken());
+                            accountRequest.setPayload(authPayload.getBytes(StandardCharsets.UTF_8));
+
+                            // TODO: deviceId must be registered after session
+                            // granted
+                            Logger.d("Adding deviceId to session: " + deviceId);
+                            sessionManager.addSession(deviceId, ctx);
+                            break;
+
+                        default:
+                            Logger.e("Unsupported request type");
+                            break;
+                    }
+
+                    rdClient.getChannelFuture().channel().attr(keyRDClient)
+                            .set(ctx);
+
+                    // Add original request to list for future use
+                    asClient.getChannelFuture().channel().attr(keyAccountClient)
+                            .get().add(request);
+                    asClient.sendRequest(accountRequest);
+                    return;
+
+                case Constants.WELL_KNOWN_URI:
+                    switch (request.getRequestMethod()) {
+                        case GET:
+                            userId = ctx.channel()
+                                    .attr(Constants.Attribute_UserId).get();
+                            authPayload = String.format("{\"userid\":\"%s\"}",
+                                    userId);
+                            accountRequest = new CoapRequest(CoapMethod.GET);
+                            accountRequest.setUriPath(Constants.ACCOUNT_URI);
+                            accountRequest.setUriQuery("reqtype=find");
+                            accountRequest.setToken(request.getToken());
+                            accountRequest.setPayload(authPayload.getBytes());
+                            break;
+
+                        default:
+                            Logger.e("Unsupported request type");
+                            break;
+                    }
+
+                    rdClient.getChannelFuture().channel().attr(keyRDClient)
+                            .set(ctx);
+
+                    // Add original request to list for future use
+                    asClient.getChannelFuture().channel().attr(keyAccountClient)
+                            .get().add(request);
+                    asClient.sendRequest(accountRequest);
+                    return;
+
+                case Constants.KEEP_ALIVE_URI:
+                    break;
+
+                default:
+                    List<String> uriPathList = request.getUriPathSegments();
+                    String originUriPathList = request.getUriPath();
+                    Logger.i("uriPahtList: " + uriPathList.toString());
+                    String ciAddress = uriPathList.get(0);
+                    String did = uriPathList.get(1);
+
+                    Logger.i("CI address: " + ciAddress);
+                    Logger.i("did: " + did);
+
+                    // TODO: getMyIP ?
+                    String hostAddress = Net.getMyIpAddress().replace("/", "");
+                    Logger.i("hostAddress : " + hostAddress);
+                    // if published CI is mine
+                    if (hostAddress.equals(ciAddress) == true) {
+                        // find ctx about did, and send msg
+                        Logger.d("published CI is mine");
+                        String resource = new String();
+                        List<String> pathSegments = uriPathList.subList(2,
+                                uriPathList.size());
+                        for (String path : pathSegments) {
+                            resource += "/";
+                            resource += path;
+                        }
+                        Logger.i("resource: " + resource);
+                        request.setUriPath(resource);
+
+                        ChannelHandlerContext deviceCtx = sessionManager
+                                .querySession(did);
+                        if (deviceCtx != null) {
+                            deviceCtx.attr(keyDevice).set(ctx);
+                            deviceCtx.writeAndFlush(request);
+                        } else {
+                            Logger.e("deviceCtx is null");
+                            response = new CoapResponse(CoapStatus.FORBIDDEN);
+                            response.setToken(request.getToken());
+                            ctx.writeAndFlush(response);
+                        }
+                    } else {
+                        // if CI is not connected, connect and send msg
+                        CoapClient otherCI = null;
+                        synchronized (ciRelayClients) {
+                            otherCI = ciRelayClients.get(ciAddress);
+                            if (otherCI == null) {
+                                otherCI = new CoapClient();
+                                otherCI.startClient(
+                                        new InetSocketAddress(ciAddress, 5683));
+                                ciRelayClients.put(ciAddress, otherCI);
+                            }
+                        }
+                        request.setUriPath(originUriPathList);
+                        otherCI.sendRequest(request);
+                    }
+                    return;
+            }
+
+        } else if (msg instanceof CoapResponse) {
+            if (ctx.attr(keyDevice).get() != null) {
+                Logger.i("ctx.channel : "
+                        + ctx.attr(keyDevice).get().channel().toString());
+                ctx.attr(keyDevice).get().writeAndFlush(msg);
+                return;
+            }
+        }
+
+        super.channelRead(ctx, msg);
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+
+        cause.printStackTrace();
+        ctx.close();
+    }
+}
diff --git a/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/resources/KeepAliveResource.java b/cloud/interface/src/main/java/org/iotivity/cloud/ciserver/resources/KeepAliveResource.java
new file mode 100644 (file)
index 0000000..a2424a0
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.ciserver.resources;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.iotivity.cloud.base.Resource;
+import org.iotivity.cloud.base.SessionManager;
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+import org.iotivity.cloud.base.protocols.coap.CoapResponse;
+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.ChannelHandlerContext;
+
+/**
+ *
+ * This class provides a set of APIs to use KeepAlive Resource for ensuring the
+ * connection.
+ *
+ */
+public class KeepAliveResource extends Resource {
+
+    private int[]                                intervals;
+    private HashMap<ChannelHandlerContext, Long> connectPool;
+    private Timer                                timer;
+    private Cbor<HashMap<String, Integer>>       cbor;
+    private SessionManager                       sessionManager = null;
+
+    public void setIntervals(int[] intervals) {
+        this.intervals = intervals;
+    }
+
+    public int[] getIntervals() {
+        return this.intervals;
+    }
+
+    public KeepAliveResource(SessionManager sessionManager, int[] intervals) {
+        setUri(Constants.KEEP_ALIVE_URI);
+        setIntervals(intervals);
+        this.sessionManager = sessionManager;
+        connectPool = new HashMap<ChannelHandlerContext, Long>();
+        timer = new Timer();
+        timer.schedule(new KeepAliveTask(), 30000, 60000);
+        cbor = new Cbor<HashMap<String, Integer>>();
+    }
+
+    /**
+     * API for receiving message(message to keepalive resource)
+     * 
+     * @param ctx
+     *            ChannelHandlerContext of request message
+     * @param request
+     *            CoAP request message
+     */
+    @Override
+    public void onRequestReceived(ChannelHandlerContext ctx,
+            CoapRequest request) {
+
+        CoapResponse response = null;
+
+        switch (request.getRequestMethod()) {
+            // First message to KeepAlive from resource
+            case GET:
+                if (intervals != null) {
+                    response = makePingConfigMessage(request);
+                    connectPool.put(ctx, System.currentTimeMillis()
+                            + (intervals[0] * (long) 60000));
+                }
+                break;
+            // interval Message to KeepAlive After receiving GET Message
+            case PUT:
+                HashMap<String, Integer> payloadData = null;
+                payloadData = cbor.parsePayloadFromCbor(request.getPayload(),
+                        new HashMap<String, Integer>().getClass());
+
+                Logger.d("Receive payloadData : " + payloadData);
+                Logger.d("interval : " + payloadData.get("in"));
+
+                connectPool.put(ctx, System.currentTimeMillis()
+                        + (payloadData.get("in") * (long) 60000));
+
+                response = makeResponse(request);
+                break;
+
+            case POST:
+                break;
+
+            case DELETE:
+                break;
+        }
+
+        ctx.writeAndFlush(response);
+    }
+
+    /**
+     * API for making response to Resource
+     * 
+     * @param request
+     *            ChannelHandlerContext of request message
+     */
+    private CoapResponse makeResponse(CoapRequest request) {
+        CoapResponse response = new CoapResponse(CoapStatus.VALID);
+        response.setToken(request.getToken());
+
+        return response;
+    }
+
+    /**
+     * API for making interval and first response to Resource
+     * 
+     * @param request
+     *            ChannelHandlerContext of request message
+     */
+    private CoapResponse makePingConfigMessage(CoapRequest request) {
+        CoapResponse response = new CoapResponse(CoapStatus.CONTENT);
+        response.setToken(request.getToken());
+
+        HashMap<String, int[]> payloadData = new HashMap<String, int[]>();
+        payloadData.put("inarray", intervals);
+
+        byte[] cborData = cbor.encodingPayloadToCbor(payloadData);
+
+        response.setPayload(cborData);
+
+        Logger.d("Send payloadData : " + payloadData);
+
+        return response;
+    }
+
+    /**
+     * API for managing session
+     */
+    public class KeepAliveTask extends TimerTask {
+
+        @Override
+        public void run() {
+            Map<ChannelHandlerContext, Long> map = Collections
+                    .synchronizedMap(connectPool);
+            Set<ChannelHandlerContext> keySet = map.keySet();
+            ArrayList<ChannelHandlerContext> deleteList = new ArrayList<ChannelHandlerContext>();
+            Iterator<ChannelHandlerContext> iterator = null;
+            synchronized (map) {
+                iterator = keySet.iterator();
+                Long currentTime = System.currentTimeMillis();
+                // check interval
+                while (iterator.hasNext()) {
+                    ChannelHandlerContext key = iterator.next();
+                    Long lifeTime = (Long) map.get(key);
+                    Logger.d("KeepAliveTask Operating : "
+                            + key.channel().toString() + ", Time : "
+                            + (lifeTime - currentTime));
+                    if (lifeTime < currentTime) {
+                        deleteList.add(key);
+                    }
+                }
+
+            }
+            iterator = deleteList.iterator();
+            // remove session
+            while (iterator.hasNext()) {
+                ChannelHandlerContext key = iterator.next();
+                Logger.d("KeepAliveTask Remove");
+                connectPool.remove(key);
+                sessionManager.removeSessionByChannel(key);
+                key.close();
+            }
+        }
+    }
+}
diff --git a/cloud/resourcedirectory/.classpath b/cloud/resourcedirectory/.classpath
new file mode 100644 (file)
index 0000000..f619a53
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="target/classes" path="src/main/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/cloud/resourcedirectory/.gitignore b/cloud/resourcedirectory/.gitignore
new file mode 100644 (file)
index 0000000..b83d222
--- /dev/null
@@ -0,0 +1 @@
+/target/
diff --git a/cloud/resourcedirectory/.project b/cloud/resourcedirectory/.project
new file mode 100644 (file)
index 0000000..a12b34d
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>CloudResourceDirectory</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.m2e.core.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.m2e.core.maven2Nature</nature>
+       </natures>
+</projectDescription>
diff --git a/cloud/resourcedirectory/README b/cloud/resourcedirectory/README
new file mode 100644 (file)
index 0000000..9b8623f
--- /dev/null
@@ -0,0 +1,29 @@
+This project contains the Resource Directory(RD) Server code.
+
+Build and Run
+
+1) Install Apache Maven if you don't have it
+
+       http://maven.apache.org
+
+2) Install Mongo DB if you don't have it
+
+       http://www.mongodb.org/downloads
+
+3) Build a CloudStack. If you are building first time, then build the stack.
+
+       go to "stack" folder in root directory
+       $ mvn install
+
+4) Build a .jar file
+
+       $ mvn install
+
+       - The CloudResourceDirectory-0.0.1-SNAPSHOT.jar file will be placed in the "target" folder
+
+5) Run .jar file
+
+       go to "target" folder
+       $ java -jar CloudResourceDirectory-0.0.1-SNAPSHOT.jar arg1(RD CoAP Server Port)
+       e.g java -jar CloudResourceDirectory-0.0.1-SNAPSHOT.jar 5684
+
diff --git a/cloud/resourcedirectory/pom.xml b/cloud/resourcedirectory/pom.xml
new file mode 100644 (file)
index 0000000..8976aba
--- /dev/null
@@ -0,0 +1,75 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <groupId>org.iotivity.cloud</groupId>
+       <artifactId>CloudResourceDirectory</artifactId>
+       <version>0.0.1-SNAPSHOT</version>
+
+       <properties>
+               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+       </properties>
+
+       <dependencies>
+               <dependency>
+                       <groupId>org.iotivity.cloud</groupId>
+                       <artifactId>CloudStack</artifactId>
+                       <version>0.0.1-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.mongodb</groupId>
+                       <artifactId>mongo-java-driver</artifactId>
+                       <version>3.2.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <version>4.12</version>
+               </dependency>
+       </dependencies>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <inherited>true</inherited>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <configuration>
+                                       <source>1.7</source>
+                                       <target>1.7</target>
+                                       <encoding>UTF-8</encoding>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-jar-plugin</artifactId>
+                               <configuration>
+                                       <archive>
+                                               <manifest>
+                                                       <mainClass>org.iotivity.cloud.rdserver.ResourceDirectoryServer</mainClass>
+                                                       <addClasspath>true</addClasspath>
+                                                       <classpathPrefix>lib/</classpathPrefix>
+                                               </manifest>
+                                       </archive>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-dependency-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                               <id>copy-dependencies</id>
+                                               <phase>package</phase>
+                                               <goals>
+                                                       <goal>copy-dependencies</goal>
+                                               </goals>
+                                       </execution>
+                               </executions>
+                               <configuration>
+                                       <outputDirectory>target/lib</outputDirectory>
+                                       <overWriteIfNewer>true</overWriteIfNewer>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+
+</project>
\ No newline at end of file
diff --git a/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/Constants.java b/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/Constants.java
new file mode 100644 (file)
index 0000000..9aa54b0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.rdserver;
+
+public class Constants {
+    public static final String RD_TABLE   = "RD_TABLE";
+    public static final String RD_DB_NAME = "RDDB";
+
+    public static final String RD_URI = "oic/rd";
+
+    public static final String RS_DEVICE_NAME             = "n";
+    public static final String RS_DEVICE_ID               = "di";
+    public static final String RS_BASE_URI                = "baseURI";
+    public static final String RS_BITMAP                  = "bm";
+    public static final String RS_HOSTING_PORT            = "port";
+    public static final String RS_INS                     = "ins";
+    public static final String RS_RTS                     = "rts";
+    public static final String RS_DREL                    = "drel";
+    public static final String RS_TTL                     = "ttl";
+    public static final String RS_HREF                    = "href";
+    public static final String RS_RESOURCE_TYPE           = "rt";
+    public static final String RS_INTERFACE               = "if";
+    public static final String RS_REL                     = "rel";
+    public static final String RS_OBS                     = "obs";
+    public static final String RS_TITLE                   = "title";
+    public static final String RS_URI                     = "uri";
+    public static final String RS_MEDIA_TYPE              = "mt";
+    public static final String RS_RESOURCE_TYPE_RDPUBLISH = "oic.wk.rdpub";
+
+    public static final String RS_SEARCH_TYPE             = "st";
+    public static final String RS_SEARCH_TYPE_DEVICE_LIST = "didList";
+    public static final String RS_DEVICE_LIST_KEY         = "devices";
+}
diff --git a/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/JSONUtil.java b/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/JSONUtil.java
new file mode 100644 (file)
index 0000000..8907a44
--- /dev/null
@@ -0,0 +1,51 @@
+package org.iotivity.cloud.rdserver;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class JSONUtil {
+
+    private static ObjectMapper mapper = new ObjectMapper();
+
+    public ArrayList<String> parseJSON(byte[] payload, String key) {
+
+        if (payload == null)
+            return null;
+
+        ArrayList<String> value = null;
+
+        try {
+            @SuppressWarnings("unchecked")
+            Map<String, ArrayList<String>> jsonMap = mapper.readValue(payload,
+                    Map.class);
+            value = jsonMap.get(key);
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+
+        return value;
+    }
+
+    public byte[] writeJSON(HashMap<Object, Object> data) throws Exception {
+        if (data == null)
+            return null;
+
+        byte[] json = null;
+        try {
+            json = mapper.writeValueAsBytes(data);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+
+        if (json == null)
+            json = "{}".getBytes(StandardCharsets.UTF_8);
+
+        return json;
+    }
+}
diff --git a/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/MongoDB.java b/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/MongoDB.java
new file mode 100644 (file)
index 0000000..5e1c1bc
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.rdserver;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.bson.Document;
+import org.iotivity.cloud.rdserver.resources.LinksPayloadFormat;
+import org.iotivity.cloud.rdserver.resources.PublishPayloadFormat;
+
+import com.mongodb.MongoClient;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoCursor;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.model.Filters;
+
+/**
+ *
+ * This class provides a set of APIs to use MongoDB APIs.
+ *
+ */
+public class MongoDB {
+
+    private MongoClient   mongoClient = null;
+    private MongoDatabase db          = null;
+
+    /**
+     * API creating MongoClient and initializing MongoDatabase
+     *
+     * @param dbname
+     *            database name to create MongoDatabase
+     * @throws Exception
+     */
+    public MongoDB(String dbname) throws Exception {
+        mongoClient = new MongoClient();
+        mongoClient.dropDatabase(dbname);
+        db = mongoClient.getDatabase(dbname);
+    }
+
+    /**
+     * API creating collection
+     *
+     * @param tableName
+     *            collection name
+     */
+    public void createTable(String tableName) {
+        db.createCollection(tableName);
+    }
+
+    /**
+     * API deleting collection
+     *
+     * @param tableName
+     *            collection name
+     */
+    public void deleteTable(String tableName) {
+        db.getCollection(tableName).drop();
+    }
+
+    private ArrayList<Document> createDocuments(
+            PublishPayloadFormat publishPayloadFormat) {
+
+        Iterator<LinksPayloadFormat> linksPayloadFormatIter = publishPayloadFormat
+                .getLinks().iterator();
+        ArrayList<Document> docList = new ArrayList<Document>();
+
+        while (linksPayloadFormatIter.hasNext()) {
+            LinksPayloadFormat links = linksPayloadFormatIter.next();
+            Document doc = new Document(Constants.RS_DEVICE_NAME,
+                    publishPayloadFormat.getDeviceName())
+                            .append(Constants.RS_DEVICE_ID,
+                                    publishPayloadFormat.getDi())
+                            .append(Constants.RS_BASE_URI,
+                                    publishPayloadFormat.getBaseUri())
+                            .append(Constants.RS_BITMAP,
+                                    publishPayloadFormat.getBitmap())
+                            .append(Constants.RS_HOSTING_PORT,
+                                    publishPayloadFormat.getPort())
+                            .append(Constants.RS_INS,
+                                    publishPayloadFormat.getIns())
+                            .append(Constants.RS_RTS,
+                                    publishPayloadFormat.getRts())
+                            .append(Constants.RS_DREL,
+                                    publishPayloadFormat.getDrel())
+                            .append(Constants.RS_TTL,
+                                    publishPayloadFormat.getTtl())
+                            .append(Constants.RS_HREF, links.getHref())
+                            .append(Constants.RS_RESOURCE_TYPE, links.getRt())
+                            .append(Constants.RS_INTERFACE, links.getItf())
+                            .append(Constants.RS_REL, links.getRel())
+                            .append(Constants.RS_OBS, links.isObs())
+                            .append(Constants.RS_TITLE, links.getTitle())
+                            .append(Constants.RS_URI, links.getUri())
+                            .append(Constants.RS_INS, links.getIns())
+                            .append(Constants.RS_MEDIA_TYPE, links.getMt());
+            docList.add(doc);
+        }
+
+        return docList;
+    }
+
+    private PublishPayloadFormat convertDocumentToResourceFormat(Document doc) {
+        PublishPayloadFormat publishPayloadFormat = new PublishPayloadFormat();
+        LinksPayloadFormat linksPayloadFormat = new LinksPayloadFormat();
+        ArrayList<LinksPayloadFormat> list = new ArrayList<LinksPayloadFormat>();
+
+        publishPayloadFormat
+                .setDeviceName(doc.getString(Constants.RS_DEVICE_NAME));
+        publishPayloadFormat.setDi(doc.getString(Constants.RS_DEVICE_ID));
+        publishPayloadFormat.setBaseUri(doc.getString(Constants.RS_BASE_URI));
+        publishPayloadFormat.setBitmap(doc.getInteger(Constants.RS_BITMAP));
+        publishPayloadFormat.setPort(doc.getInteger(Constants.RS_HOSTING_PORT));
+        publishPayloadFormat.setIns(doc.getInteger(Constants.RS_INS));
+        publishPayloadFormat.setRts(doc.getString(Constants.RS_RTS));
+        publishPayloadFormat.setDrel(doc.getString(Constants.RS_DREL));
+        publishPayloadFormat.setTtl(doc.getInteger(Constants.RS_TTL));
+
+        linksPayloadFormat.setHref(doc.getString(Constants.RS_HREF));
+        linksPayloadFormat
+                .setRt((ArrayList<String>) doc.get(Constants.RS_RESOURCE_TYPE));
+        linksPayloadFormat
+                .setItf((ArrayList<String>) doc.get(Constants.RS_INTERFACE));
+        linksPayloadFormat.setRel(doc.getString(Constants.RS_REL));
+        linksPayloadFormat.setObs(doc.getBoolean(Constants.RS_OBS));
+        linksPayloadFormat.setTitle(doc.getString(Constants.RS_TITLE));
+        linksPayloadFormat.setUri(doc.getString(Constants.RS_URI));
+        linksPayloadFormat.setIns(doc.getInteger(Constants.RS_INS));
+        linksPayloadFormat
+                .setMt((ArrayList<String>) doc.get(Constants.RS_MEDIA_TYPE));
+
+        list.add(linksPayloadFormat);
+        publishPayloadFormat.setLinks(list);
+
+        return publishPayloadFormat;
+    }
+
+    /**
+     * API for storing information of published resources
+     *
+     * @param publishPayloadFormat
+     *            information of published resources to store in collection
+     * @param tablename
+     *            collection name
+     */
+    public void createResource(PublishPayloadFormat publishPayloadFormat,
+            String tablename) {
+        ArrayList<Document> docList = createDocuments(publishPayloadFormat);
+        Iterator<Document> docIter = docList.iterator();
+
+        MongoCollection<Document> collection = db.getCollection(tablename);
+
+        while (docIter.hasNext()) {
+            Document doc = docIter.next();
+
+            if (collection.findOneAndReplace(
+                    Filters.and(Filters.eq(Constants.RS_DEVICE_ID,
+                            doc.get(Constants.RS_DEVICE_ID)),
+                    Filters.eq(Constants.RS_INS, doc.get(Constants.RS_INS))),
+                    doc) == null) {
+
+                collection.insertOne(doc);
+            }
+        }
+    }
+
+    /**
+     * API for finding resources matched filterValue of filterKey in collection
+     *
+     * @param filterKey
+     *            field name in collection
+     * @param filterValue
+     *            field value about field name
+     * @param tablename
+     *            collection name
+     * @return ArrayList<PublishPayloadFormat> - array list of resource
+     *         information
+     */
+    public ArrayList<PublishPayloadFormat> readResource(String filterKey,
+            String filterValue, String tablename) {
+        MongoCollection<Document> collection = db.getCollection(tablename);
+        ArrayList<PublishPayloadFormat> resourceFormatList = new ArrayList<PublishPayloadFormat>();
+        MongoCursor<Document> cursor = collection
+                .find(Filters.eq(filterKey, filterValue)).iterator();
+        try {
+            while (cursor.hasNext()) {
+                Document doc = cursor.next();
+                resourceFormatList.add(convertDocumentToResourceFormat(doc));
+            }
+        } finally {
+            cursor.close();
+        }
+
+        return resourceFormatList;
+    }
+
+    /**
+     * API for finding resources matched filterValue of filterKey and a
+     * particular device ID in collection
+     *
+     * @param di
+     *            device id
+     * @param filterKey
+     *            field name in collection
+     * @param filterValue
+     *            field value about field name
+     * @param tablename
+     *            collection name
+     * @return ArrayList<PublishPayloadFormat> - array list of resource
+     *         information
+     */
+    public ArrayList<PublishPayloadFormat> readResourceAboutDid(String di,
+            String filterKey, String filterValue, String tablename) {
+        MongoCollection<Document> collection = db.getCollection(tablename);
+        ArrayList<PublishPayloadFormat> resourceFormatList = new ArrayList<PublishPayloadFormat>();
+        MongoCursor<Document> cursor = collection
+                .find(Filters.and(Filters.eq(Constants.RS_DEVICE_ID, di),
+                        Filters.eq(filterKey, filterValue)))
+                .iterator();
+        try {
+            while (cursor.hasNext()) {
+                Document doc = cursor.next();
+                resourceFormatList.add(convertDocumentToResourceFormat(doc));
+            }
+        } finally {
+            cursor.close();
+        }
+
+        return resourceFormatList;
+    }
+
+    /**
+     * API for deleting resources about a particular device ID in collection
+     *
+     * @param di
+     *            device id
+     * @param tablename
+     *            collection name
+     */
+    public void deleteResourceAboutDid(String di, String tablename) {
+
+        MongoCollection<Document> collection = db.getCollection(tablename);
+
+        collection.findOneAndDelete(Filters.eq(Constants.RS_DEVICE_ID, di));
+    }
+
+    /**
+     * API for deleting resources about a particular device ID and ins in
+     * collection
+     *
+     * @param di
+     *            device id
+     * @param ins
+     *            ins
+     * @param tablename
+     *            collection name
+     */
+    public void deleteResourceAboutDidAndIns(String di, String ins,
+            String tablename) {
+
+        MongoCollection<Document> collection = db.getCollection(tablename);
+
+        collection.findOneAndDelete(
+                Filters.and(Filters.eq(Constants.RS_DEVICE_ID, di),
+                        Filters.eq(Constants.RS_INS, ins)));
+
+    }
+}
diff --git a/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/ResourceDirectoryServer.java b/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/ResourceDirectoryServer.java
new file mode 100644 (file)
index 0000000..29fed8f
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.rdserver;
+
+import java.net.InetSocketAddress;
+
+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");
+            return;
+        }
+
+        ResourceManager resourceManager = null;
+
+        CoapServer coapServer = null;
+
+        coapServer = new CoapServer();
+
+        resourceManager = new ResourceManager();
+
+        coapServer.addHandler(resourceManager);
+
+        resourceManager.registerResource(new ResourceDirectoryResource());
+
+        coapServer
+                .startServer(new InetSocketAddress(Integer.parseInt(args[0])));
+    }
+
+}
diff --git a/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/resources/LinksPayloadFormat.java b/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/resources/LinksPayloadFormat.java
new file mode 100644 (file)
index 0000000..0f6a6c5
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.rdserver.resources;
+
+import java.util.ArrayList;
+
+public class LinksPayloadFormat {
+    /** This is the target relative URI. */
+    String            href;
+    /**
+     * Resource Type - A standard OIC specified or vendor defined resource type
+     * of the resource referenced by the target URI.
+     */
+    ArrayList<String> rt;
+    /**
+     * Interface - The interfaces supported by the resource referenced by the
+     * target URI.
+     */
+    ArrayList<String> itf;
+    /**
+     * The relation of the target URI referenced by the link to the context URI;
+     * The default value is null.
+     */
+    String            rel;
+    /**
+     * Specifies if the resource referenced by the target URIis observable or
+     * not.
+     */
+    boolean           obs;
+    /**
+     * A title for the link relation. Can be used by the UI to provide a
+     * context.
+     */
+    String            title;
+    /**
+     * This is used to override the context URI e.g. override the URI of the
+     * containing collection.
+     */
+    String            uri;
+    /**
+     * The instance identifier for this web link in an array of web links - used
+     * in links.
+     */
+    int               ins;
+    /**
+     * A hint of the media type of the representation of the resource referenced
+     * by the target URI.
+     */
+    ArrayList<String> mt;
+
+    public LinksPayloadFormat() {
+        rt = new ArrayList<String>();
+        itf = new ArrayList<String>();
+        mt = new ArrayList<String>();
+    }
+
+    public String getHref() {
+        return href;
+    }
+
+    public void setHref(String href) {
+        this.href = href;
+    }
+
+    public ArrayList<String> getRt() {
+        return rt;
+    }
+
+    public void setRt(ArrayList<String> rt) {
+        this.rt = rt;
+    }
+
+    public ArrayList<String> getItf() {
+        return itf;
+    }
+
+    public void setItf(ArrayList<String> itf) {
+        this.itf = itf;
+    }
+
+    public String getRel() {
+        return rel;
+    }
+
+    public void setRel(String rel) {
+        this.rel = rel;
+    }
+
+    public boolean isObs() {
+        return obs;
+    }
+
+    public void setObs(boolean obs) {
+        this.obs = obs;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    public int getIns() {
+        return ins;
+    }
+
+    public void setIns(int ins) {
+        this.ins = ins;
+    }
+
+    public ArrayList<String> getMt() {
+        return mt;
+    }
+
+    public void setMt(ArrayList<String> mt) {
+        this.mt = mt;
+    }
+}
\ No newline at end of file
diff --git a/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/resources/PublishPayloadFormat.java b/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/resources/PublishPayloadFormat.java
new file mode 100644 (file)
index 0000000..1fe0191
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.rdserver.resources;
+
+import java.util.ArrayList;
+
+public class PublishPayloadFormat {
+
+    /** Name of tags. */
+    String deviceName;
+    /** Device identifier. */
+    String di;
+    /** The base URI where the resources are hold. */
+    String baseUri;
+    /** Bitmap holds observable, discoverable, secure option flag. */
+    int    bitmap;
+    /** Port set in case, the secure flag is set above. */
+    int    port;
+    /** Id for each set of links i.e. tag. */
+    int    ins;
+    /**
+     * Defines the list of allowable resource types (for Target and anchors) in
+     * links included in the collection; new links being created can only be
+     * from this list.
+     */
+    String rts;
+    /**
+     * When specified this is the default relationship to use when an OIC Link
+     * does not specify an explicit relationship with *rel* parameter.
+     */
+    String drel;
+    /** Time to keep holding resource. */
+    int    ttl;
+
+    ArrayList<LinksPayloadFormat> links;
+
+    public PublishPayloadFormat() {
+        links = new ArrayList<LinksPayloadFormat>();
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getDi() {
+        return di;
+    }
+
+    public void setDi(String di) {
+        this.di = di;
+    }
+
+    public String getBaseUri() {
+        return baseUri;
+    }
+
+    public void setBaseUri(String baseUri) {
+        this.baseUri = baseUri;
+    }
+
+    public int getBitmap() {
+        return bitmap;
+    }
+
+    public void setBitmap(int bitmap) {
+        this.bitmap = bitmap;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public int getIns() {
+        return ins;
+    }
+
+    public void setIns(int ins) {
+        this.ins = ins;
+    }
+
+    public String getRts() {
+        return rts;
+    }
+
+    public void setRts(String rts) {
+        this.rts = rts;
+    }
+
+    public String getDrel() {
+        return drel;
+    }
+
+    public void setDrel(String drel) {
+        this.drel = drel;
+    }
+
+    public int getTtl() {
+        return ttl;
+    }
+
+    public void setTtl(int ttl) {
+        this.ttl = ttl;
+    }
+
+    public ArrayList<LinksPayloadFormat> getLinks() {
+        return links;
+    }
+
+    public void setLinks(ArrayList<LinksPayloadFormat> links) {
+        this.links = links;
+    }
+}
diff --git a/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/resources/ResourceDirectoryResource.java b/cloud/resourcedirectory/src/main/java/org/iotivity/cloud/rdserver/resources/ResourceDirectoryResource.java
new file mode 100644 (file)
index 0000000..e2d1502
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.rdserver.resources;
+
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.iotivity.cloud.base.Resource;
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+import org.iotivity.cloud.base.protocols.coap.CoapResponse;
+import org.iotivity.cloud.base.protocols.coap.enums.CoapOption;
+import org.iotivity.cloud.base.protocols.coap.enums.CoapStatus;
+import org.iotivity.cloud.rdserver.Constants;
+import org.iotivity.cloud.rdserver.JSONUtil;
+import org.iotivity.cloud.rdserver.MongoDB;
+import org.iotivity.cloud.util.Cbor;
+import org.iotivity.cloud.util.Logger;
+import org.iotivity.cloud.util.Net;
+
+import io.netty.channel.ChannelHandlerContext;
+
+/**
+ *
+ * This class provides a set of APIs relating Resource Directory
+ *
+ */
+public class ResourceDirectoryResource extends Resource {
+
+    private Cbor<ArrayList<Object>> cbor;
+    private MongoDB                 mongoDB;
+
+    public ResourceDirectoryResource() {
+        setUri(Constants.RD_URI);
+        cbor = new Cbor<ArrayList<Object>>();
+        try {
+            mongoDB = new MongoDB(Constants.RD_DB_NAME);
+            mongoDB.createTable(Constants.RD_TABLE);
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void onRequestReceived(ChannelHandlerContext ctx,
+            CoapRequest request) {
+
+        Logger.d("ResourceDirectoryResource IN");
+
+        if (ctx == null || request == null) {
+            Logger.d("ctx or request msg is null");
+        }
+
+        else {
+            switch (request.getRequestMethod()) {
+                case GET:
+                    Logger.d("Request message is GET message");
+                    try {
+                        handleGetRequest(ctx, request);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    break;
+
+                case PUT:
+                    Logger.d("Request message is PUT message");
+                    break;
+
+                case POST:
+                    Logger.d("Request message is POST message");
+                    try {
+                        handlePostRequest(ctx, request);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    break;
+
+                case DELETE:
+                    Logger.d("Request message is DELETE message");
+                    try {
+                        handleDeleteRequest(ctx, request);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    break;
+            }
+        }
+    }
+
+    private CoapResponse makePublishResponse(CoapRequest request)
+            throws Exception {
+        CoapResponse response = new CoapResponse(CoapStatus.CREATED);
+        response.setToken(request.getToken());
+        return response;
+    }
+
+    private CoapResponse makeDeleteResponse(CoapRequest request)
+            throws Exception {
+        CoapResponse response = new CoapResponse(CoapStatus.DELETED);
+        response.setToken(request.getToken());
+        return response;
+    }
+
+    private CoapResponse makeDiscoveryResponse(CoapRequest request,
+            ArrayList<PublishPayloadFormat> foundResource) throws Exception {
+
+        CoapResponse response = new CoapResponse(CoapStatus.CONTENT);
+        response.setToken(request.getToken());
+
+        // make payload
+        ArrayList<HashMap<Object, Object>> discoverPayload = new ArrayList<HashMap<Object, Object>>();
+
+        for (PublishPayloadFormat pubPayload : foundResource) {
+
+            LinksPayloadFormat links = pubPayload.links.get(0);
+            LinkedHashMap<Object, Object> discoverLinks = new LinkedHashMap<Object, Object>();
+            discoverLinks.put(Constants.RS_HREF, links.getHref());
+            discoverLinks.put(Constants.RS_RESOURCE_TYPE, links.getRt().get(0));
+            discoverLinks.put(Constants.RS_INTERFACE, links.getItf().get(0));
+            HashMap<Object, Object> pres = new HashMap<Object, Object>();
+            pres.put(Constants.RS_BITMAP, pubPayload.getBitmap());
+            discoverLinks.put("p", pres);
+
+            ArrayList<Object> linksArray = null;
+            for (HashMap<Object, Object> segmentPayload : discoverPayload) {
+                // exist di
+                if (segmentPayload.get(Constants.RS_DEVICE_ID)
+                        .equals(pubPayload.getDi())) {
+                    linksArray = new ArrayList<Object>();
+                    linksArray = (ArrayList<Object>) segmentPayload
+                            .get("links");
+                    linksArray.add(discoverLinks);
+                    segmentPayload.put("links", linksArray);
+                }
+            }
+            if (linksArray == null) {
+                HashMap<Object, Object> discoverRes = new HashMap<Object, Object>();
+                linksArray = new ArrayList<Object>();
+                discoverRes.put(Constants.RS_DEVICE_ID, pubPayload.getDi());
+                linksArray.add(discoverLinks);
+                discoverRes.put("links", linksArray);
+                discoverPayload.add(discoverRes);
+            }
+        }
+
+        // TODO : device id is decoded to byte in IoTivity. So, temporarily we
+        // cast the type of device id to byte.
+        for (HashMap<Object, Object> segmentPayload : discoverPayload) {
+            String stringDi = segmentPayload.get(Constants.RS_DEVICE_ID)
+                    .toString();
+            segmentPayload.put(Constants.RS_DEVICE_ID, stringDi.getBytes(StandardCharsets.UTF_8));
+        }
+
+        Logger.i("discoverPayload :" + discoverPayload.toString());
+
+        byte[] bytes = ByteBuffer.allocate(4).putInt(60).array();
+        response.addOption(CoapOption.CONTENT_FORMAT.getvalue(), bytes);
+
+        byte[] encodedPaylod = cbor.encodingPayloadToCbor(discoverPayload);
+        response.setPayload(encodedPaylod);
+
+        return response;
+
+    }
+
+    private HashMap<String, String> extractFiltersFromQuery(List<String> query)
+            throws Exception {
+
+        if (query == null) {
+            throw new IllegalArgumentException("query is null!");
+        }
+
+        HashMap<String, String> filters = new HashMap<String, String>();
+        for (String queryPara : query) {
+            StringTokenizer keyValuePair = new StringTokenizer(queryPara, "=");
+            if (keyValuePair.countTokens() < 2) {
+                // query error
+                filters = null;
+            } else {
+                String key = keyValuePair.nextToken();
+                String value = keyValuePair.nextToken();
+                if (key.equals(Constants.RS_INTERFACE)) {
+                    filters.put(Constants.RS_INTERFACE, value);
+                } else if (key.equals(Constants.RS_RESOURCE_TYPE)) {
+                    filters.put(Constants.RS_RESOURCE_TYPE, value);
+                } else if (key.equals(Constants.RS_DEVICE_ID)) {
+                    filters.put(Constants.RS_DEVICE_ID, value);
+                } else if (key.equals(Constants.RS_INS)) {
+                    filters.put(Constants.RS_INS, value);
+                } else if (key.equals(Constants.RS_SEARCH_TYPE)) {
+                    filters.put(Constants.RS_SEARCH_TYPE, value);
+                }
+            }
+        }
+
+        return filters;
+    }
+
+    /**
+     * API for handling GET message(message to discovery resources)
+     *
+     * @param ctx
+     *            ChannelHandlerContext of request message
+     * @param request
+     *            CoAP request message
+     * @throws Exception
+     */
+    public void handleGetRequest(ChannelHandlerContext ctx, CoapRequest request)
+            throws Exception {
+        HashMap<String, String> filters = extractFiltersFromQuery(
+                request.getUriQuerySegments());
+
+        ArrayList<PublishPayloadFormat> foundResource = null;
+
+        if (filters == null) {
+            throw new IllegalArgumentException("filters is null");
+        } else if (filters.get(Constants.RS_SEARCH_TYPE) == null) {
+            Logger.d("st is null, so this is the get msg about public devices");
+            if (filters.get(Constants.RS_INTERFACE) != null) {
+                foundResource = mongoDB.readResource(Constants.RS_INTERFACE,
+                        filters.get(Constants.RS_INTERFACE),
+                        Constants.RD_TABLE);
+            } else if (filters.get(Constants.RS_RESOURCE_TYPE) != null) {
+                foundResource = mongoDB.readResource(Constants.RS_RESOURCE_TYPE,
+                        filters.get(Constants.RS_RESOURCE_TYPE),
+                        Constants.RD_TABLE);
+            } else {
+                throw new IllegalArgumentException("rt & if is null");
+            }
+
+            CoapResponse response = makeDiscoveryResponse(request,
+                    foundResource);
+            ctx.writeAndFlush(response);
+
+        } else {
+            if (filters.get(Constants.RS_SEARCH_TYPE)
+                    .equals(Constants.RS_SEARCH_TYPE_DEVICE_LIST)) {
+                Logger.d(
+                        "st is not null, so this is the get msg about private devices");
+                // parse payload
+                byte[] payload = request.getPayload();
+                JSONUtil util = new JSONUtil();
+                ArrayList<String> deviceList = util.parseJSON(payload,
+                        Constants.RS_DEVICE_LIST_KEY);
+                if (deviceList == null) {
+                    throw new IllegalArgumentException("deviceList is null");
+                }
+
+                if (filters.get(Constants.RS_INTERFACE) != null) {
+                    foundResource = new ArrayList<PublishPayloadFormat>();
+                    for (String deviceId : deviceList) {
+                        foundResource.addAll(mongoDB.readResourceAboutDid(
+                                deviceId, Constants.RS_INTERFACE,
+                                filters.get(Constants.RS_INTERFACE),
+                                Constants.RD_TABLE));
+                    }
+                } else if (filters.get(Constants.RS_RESOURCE_TYPE) != null) {
+                    foundResource = new ArrayList<PublishPayloadFormat>();
+                    for (String deviceId : deviceList) {
+                        foundResource.addAll(mongoDB.readResourceAboutDid(
+                                deviceId, Constants.RS_RESOURCE_TYPE,
+                                filters.get(Constants.RS_RESOURCE_TYPE),
+                                Constants.RD_TABLE));
+                    }
+                } else {
+                    throw new IllegalArgumentException("rt & if is null");
+                }
+
+                CoapResponse response = makeDiscoveryResponse(request,
+                        foundResource);
+                ctx.writeAndFlush(response);
+            } else {
+                throw new IllegalArgumentException("value of st is not corret");
+            }
+        }
+    }
+
+    /**
+     * API for handling POST message(message to publish or update resources)
+     *
+     * @param ctx
+     *            ChannelHandlerContext of request message
+     * @param request
+     *            CoAP request message
+     * @throws Exception
+     */
+    public void handlePostRequest(ChannelHandlerContext ctx,
+            CoapRequest request) throws Exception {
+
+        HashMap<String, String> filters = extractFiltersFromQuery(
+                request.getUriQuerySegments());
+
+        if (filters == null) {
+            throw new IllegalArgumentException("filters is null");
+        } else if (filters.get(Constants.RS_RESOURCE_TYPE) == null) {
+            throw new IllegalArgumentException("rt is null");
+        } else if (filters.get(Constants.RS_RESOURCE_TYPE)
+                .equals(Constants.RS_RESOURCE_TYPE_RDPUBLISH)) {
+            Logger.d("This request is publish msg!");
+
+            PublishPayloadFormat pubPayload = new PublishPayloadFormat();
+
+            String ciAddress = ((InetSocketAddress) ctx.channel()
+                    .remoteAddress()).getAddress().getHostAddress();
+
+            if (ciAddress.equalsIgnoreCase("127.0.0.1")) {
+                ciAddress = Net.getMyIpAddress().replace("/", "");
+            }
+
+            ArrayList<Object> payloadData = cbor.parsePayloadFromCbor(
+                    request.getPayload(), ArrayList.class);
+
+            Logger.i("payloadData: " + payloadData.toString());
+
+            HashMap<Object, Object> tags = (HashMap<Object, Object>) payloadData
+                    .get(0);
+
+            if (tags == null) {
+                throw new IllegalArgumentException("tags is null!");
+            }
+
+            if (tags.get(Constants.RS_DEVICE_ID) != null) {
+                pubPayload.setDi(tags.get(Constants.RS_DEVICE_ID).toString());
+                Logger.i("di : " + pubPayload.getDi());
+            } else {
+                throw new IllegalArgumentException("device id is null!");
+            }
+
+            if (tags.get(Constants.RS_DEVICE_NAME) != null) {
+                pubPayload.setDeviceName(
+                        tags.get(Constants.RS_DEVICE_NAME).toString());
+                Logger.i("device name : " + pubPayload.getDeviceName());
+            }
+
+            if (tags.get(Constants.RS_BASE_URI) != null) {
+                pubPayload
+                        .setBaseUri(tags.get(Constants.RS_BASE_URI).toString());
+                Logger.i("baseURI : " + pubPayload.getBaseUri());
+            }
+
+            if (tags.get(Constants.RS_BITMAP) != null) {
+                pubPayload.setBitmap((int) tags.get(Constants.RS_BITMAP));
+                Logger.i("bm : " + pubPayload.getBitmap());
+            }
+
+            if (tags.get(Constants.RS_HOSTING_PORT) != null) {
+                pubPayload.setPort((int) tags.get(Constants.RS_HOSTING_PORT));
+                Logger.i("port : " + pubPayload.getPort());
+            }
+
+            if (tags.get(Constants.RS_INS) != null) {
+                pubPayload.setIns((int) tags.get(Constants.RS_INS));
+                Logger.i("ins : " + pubPayload.getIns());
+            }
+
+            if (tags.get(Constants.RS_RTS) != null) {
+                pubPayload.setRts(tags.get(Constants.RS_RTS).toString());
+                Logger.i("rts : " + pubPayload.getRts());
+            }
+
+            if (tags.get(Constants.RS_DREL) != null) {
+                pubPayload.setDrel(tags.get(Constants.RS_DREL).toString());
+                Logger.i("drel : " + pubPayload.getDrel());
+            }
+
+            if (tags.get(Constants.RS_TTL) != null) {
+                pubPayload.setTtl((int) tags.get(Constants.RS_TTL));
+                Logger.i("ttl : " + pubPayload.getTtl());
+            }
+
+            ArrayList<LinkedHashMap<Object, Object>> publishLinks = (ArrayList<LinkedHashMap<Object, Object>>) payloadData
+                    .get(1);
+
+            if (publishLinks == null) {
+                throw new IllegalArgumentException("publishLinks is null!");
+            }
+
+            for (LinkedHashMap<Object, Object> o : publishLinks) {
+
+                LinksPayloadFormat storeLinks = new LinksPayloadFormat();
+
+                if (o.get(Constants.RS_HREF) != null) {
+                    String prefix = "/" + ciAddress + "/" + pubPayload.getDi();
+                    storeLinks.setHref(
+                            prefix + o.get(Constants.RS_HREF).toString());
+                    Logger.i("href : " + storeLinks.getHref());
+                }
+
+                if (o.get(Constants.RS_RESOURCE_TYPE) != null) {
+                    storeLinks.setRt((ArrayList<String>) o
+                            .get(Constants.RS_RESOURCE_TYPE));
+                    Logger.i("rt : " + storeLinks.getRt().toString());
+                }
+
+                if (o.get(Constants.RS_INTERFACE) != null) {
+                    storeLinks.setItf(
+                            (ArrayList<String>) o.get(Constants.RS_INTERFACE));
+                    Logger.i("if : " + storeLinks.getItf().toString());
+                }
+
+                if (o.get(Constants.RS_REL) != null) {
+                    storeLinks.setRel(o.get(Constants.RS_REL).toString());
+                    Logger.i("rel : " + storeLinks.getRel());
+                }
+
+                if (o.get(Constants.RS_OBS) != null) {
+                    storeLinks.setObs((boolean) o.get(Constants.RS_OBS));
+                    Logger.i("obs : " + storeLinks.isObs());
+                }
+
+                if (o.get(Constants.RS_TITLE) != null) {
+                    storeLinks.setTitle(o.get(Constants.RS_TITLE).toString());
+                    Logger.i("title : " + storeLinks.getTitle());
+                }
+
+                if (o.get(Constants.RS_URI) != null) {
+                    storeLinks.setUri(o.get(Constants.RS_URI).toString());
+                    Logger.i("uri : " + storeLinks.getUri());
+                }
+
+                if (o.get(Constants.RS_INS) != null) {
+                    storeLinks.setIns((int) (o.get(Constants.RS_INS)));
+                    Logger.i("ins : " + storeLinks.getIns());
+                }
+
+                if (o.get(Constants.RS_MEDIA_TYPE) != null) {
+                    storeLinks.setMt(
+                            (ArrayList<String>) o.get(Constants.RS_MEDIA_TYPE));
+                    Logger.i("mt : " + storeLinks.getMt().toString());
+                }
+
+                pubPayload.links.add(storeLinks);
+            }
+
+            mongoDB.createResource(pubPayload, Constants.RD_TABLE);
+
+            CoapResponse response = makePublishResponse(request);
+            ctx.writeAndFlush(response);
+
+        } else {
+            throw new IllegalArgumentException("rt is not correct");
+        }
+    }
+
+    /**
+     * API for handling Delete message(message to delete published resources)
+     *
+     * @param ctx
+     *            ChannelHandlerContext of request message
+     * @param request
+     *            CoAP request message
+     * @throws Exception
+     */
+    public void handleDeleteRequest(ChannelHandlerContext ctx,
+            CoapRequest request) throws Exception {
+        HashMap<String, String> filters = extractFiltersFromQuery(
+                request.getUriQuerySegments());
+
+        if (filters == null) {
+            throw new IllegalArgumentException("filters is null");
+        } else if (filters.get(Constants.RS_DEVICE_ID) == null) {
+            throw new IllegalArgumentException("di is null");
+        } else {
+            if (filters.get(Constants.RS_INS) == null) {
+                mongoDB.deleteResourceAboutDid(
+                        filters.get(Constants.RS_DEVICE_ID),
+                        Constants.RD_TABLE);
+            } else {
+                mongoDB.deleteResourceAboutDidAndIns(
+                        filters.get(Constants.RS_DEVICE_ID),
+                        filters.get(Constants.RS_INS), Constants.RD_TABLE);
+            }
+            CoapResponse response = makeDeleteResponse(request);
+            ctx.writeAndFlush(response);
+        }
+    }
+}
diff --git a/cloud/resourcedirectory/src/test/java/org/iotivity/cloud/testrdserver/RDServerTest.java b/cloud/resourcedirectory/src/test/java/org/iotivity/cloud/testrdserver/RDServerTest.java
new file mode 100644 (file)
index 0000000..7d5ff40
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.testrdserver;
+
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import org.iotivity.cloud.base.CoapClient;
+import org.iotivity.cloud.base.CoapServer;
+import org.iotivity.cloud.base.ResourceManager;
+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.rdserver.Constants;
+import org.iotivity.cloud.rdserver.JSONUtil;
+import org.iotivity.cloud.rdserver.resources.ResourceDirectoryResource;
+import org.iotivity.cloud.util.Cbor;
+import org.junit.Test;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+
+public class RDServerTest {
+
+    private ResourceDirectoryResource rdResource = new ResourceDirectoryResource();
+    private CoapServer                coapServer = null;
+    private CoapClient                coapClient = null;
+
+    static class CoapClientHandler
+            extends SimpleChannelInboundHandler<CoapResponse> {
+
+        ChannelHandlerContext connectCtx = null;
+
+        @Override
+        public void channelActive(ChannelHandlerContext ctx) throws Exception {
+            connectCtx = ctx;
+        }
+
+        @Override
+        protected void channelRead0(ChannelHandlerContext arg0,
+                CoapResponse arg1) throws Exception {
+            // TODO Auto-generated method stub
+
+        }
+    }
+
+    public void startServer() throws Exception {
+        coapServer = new CoapServer();
+        ResourceManager resourceManager = new ResourceManager();
+        coapServer.addHandler(resourceManager);
+        resourceManager.registerResource(new ResourceDirectoryResource());
+        coapServer.startServer(new InetSocketAddress(5683));
+    }
+
+    public ChannelHandlerContext startClient() throws Exception {
+        coapClient = new CoapClient();
+        CoapClientHandler coapHandler = new CoapClientHandler();
+        coapClient.addHandler(coapHandler);
+        coapClient.startClient(new InetSocketAddress("127.0.0.1", 5683));
+        return coapHandler.connectCtx;
+    }
+
+    public CoapRequest makePublishPayload() throws Exception {
+
+        CoapRequest request = new CoapRequest(CoapMethod.POST);
+        request.setUriPath(Constants.RD_URI);
+        request.setUriQuery("rt=oic.wk.rdPub");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+
+        ArrayList<Object> payload = new ArrayList<Object>();
+
+        HashMap<Object, Object> tags = new HashMap<Object, Object>();
+        tags.put("di", "98f7483c-5a31-4161-ba7e-9c13e0d");
+        tags.put("bm", (int) 1);
+        tags.put("ttl", (int) 86400);
+
+        ArrayList<LinkedHashMap<Object, Object>> publishLinks = new ArrayList<LinkedHashMap<Object, Object>>();
+        LinkedHashMap<Object, Object> link = new LinkedHashMap<Object, Object>();
+        link.put("href", "/a/light");
+        ArrayList<String> rt = new ArrayList<String>();
+        ArrayList<String> itf = new ArrayList<String>();
+        ArrayList<String> mt = new ArrayList<String>();
+        rt.add("core.light");
+        link.put("rt", rt);
+
+        itf.add("oic.if.baseline");
+        link.put("if", itf);
+
+        mt.add("application/json");
+        link.put("mt", mt);
+
+        link.put("ins", 1);
+
+        publishLinks.add(link);
+
+        payload.add(tags);
+        payload.add(publishLinks);
+
+        Cbor<ArrayList<Object>> cbor = new Cbor<ArrayList<Object>>();
+
+        request.setPayload(cbor.encodingPayloadToCbor(payload));
+
+        return request;
+    }
+
+    @Test
+    public void testHandlePostRequest() throws Exception {
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+
+        rdResource.handlePostRequest(ctx, makePublishPayload());
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+
+    }
+
+    @Test
+    public void testHandleGetRequest_notExistVaule() throws Exception {
+
+        CoapRequest request = new CoapRequest(CoapMethod.GET);
+        request.setUriPath(Constants.RD_URI);
+        request.setUriQuery("rt=core.light");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+
+        rdResource.handleGetRequest(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testHandleGetRequest_existValue() throws Exception {
+
+        CoapRequest request = new CoapRequest(CoapMethod.GET);
+        request.setUriPath(Constants.RD_URI);
+        request.setUriQuery("rt=core.light");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+
+        rdResource.handlePostRequest(ctx, makePublishPayload());
+
+        rdResource.handleGetRequest(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testHandleGetRequestBySt_existValue() throws Exception {
+
+        CoapRequest request = new CoapRequest(CoapMethod.GET);
+        request.setUriPath(Constants.RD_URI);
+        request.setUriQuery("rt=core.light&st=didList");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+
+        HashMap<Object, Object> data = new HashMap<Object, Object>();
+        ArrayList<String> didList = new ArrayList<String>();
+        didList.add("98f7483c-5a31-4161-ba7e-9c13e0d");
+        data.put("devices", didList);
+        JSONUtil util = new JSONUtil();
+        byte[] payload = util.writeJSON(data);
+        request.setPayload(payload);
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+
+        rdResource.handlePostRequest(ctx, makePublishPayload());
+
+        rdResource.handleGetRequest(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testHandleDeleteRequestByDi_notExistVaule() throws Exception {
+
+        CoapRequest request = new CoapRequest(CoapMethod.DELETE);
+        request.setUriPath(Constants.RD_URI);
+        request.setUriQuery("di=98f7483c-5a31-4161-ba7e-9c13e0d");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+
+        rdResource.handlePostRequest(ctx, makePublishPayload());
+
+        rdResource.handleDeleteRequest(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testHandleDeleteRequestByDi_existVaule() throws Exception {
+
+        CoapRequest request = new CoapRequest(CoapMethod.DELETE);
+        request.setUriPath(Constants.RD_URI);
+        request.setUriQuery("di=98f7483c-5a31-4161-ba7e-9c13e0d");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+
+        rdResource.handleDeleteRequest(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testHandleDeleteRequestByIns_notExistVaule() throws Exception {
+
+        CoapRequest request = new CoapRequest(CoapMethod.DELETE);
+        request.setUriPath(Constants.RD_URI);
+        request.setUriQuery("di=98f7483c-5a31-4161-ba7e-9c13e0d&ins=1");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+
+        rdResource.handleDeleteRequest(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testHandleDeleteRequestByIns_existVaule() throws Exception {
+
+        CoapRequest request = new CoapRequest(CoapMethod.DELETE);
+        request.setUriPath(Constants.RD_URI);
+        request.setUriQuery("di=98f7483c-5a31-4161-ba7e-9c13e0d&ins=1");
+        request.setToken("1234".getBytes(StandardCharsets.UTF_8));
+
+        startServer();
+        ChannelHandlerContext ctx = startClient();
+
+        rdResource.handlePostRequest(ctx, makePublishPayload());
+
+        rdResource.handleDeleteRequest(ctx, request);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+}
diff --git a/cloud/stack/.classpath b/cloud/stack/.classpath
new file mode 100644 (file)
index 0000000..366f061
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="target/classes" path="src/main/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="src" path="src/test/java"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/cloud/stack/.gitignore b/cloud/stack/.gitignore
new file mode 100644 (file)
index 0000000..b83d222
--- /dev/null
@@ -0,0 +1 @@
+/target/
diff --git a/cloud/stack/.project b/cloud/stack/.project
new file mode 100644 (file)
index 0000000..c3fbeb0
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>CloudStack</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.m2e.core.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.m2e.core.maven2Nature</nature>
+       </natures>
+</projectDescription>
diff --git a/cloud/stack/README b/cloud/stack/README
new file mode 100644 (file)
index 0000000..3811258
--- /dev/null
@@ -0,0 +1,13 @@
+This project contains the common stack for all server instances.
+
+Build
+
+1) Install Apache Maven if you don't have it
+
+       http://maven.apache.org
+
+2) Build a .jar file
+
+       $ mvn install
+
+       - The CloudStack-0.0.1-SNAPSHOT.jar file will be placed in the "target" folder.
diff --git a/cloud/stack/pom.xml b/cloud/stack/pom.xml
new file mode 100644 (file)
index 0000000..f04a936
--- /dev/null
@@ -0,0 +1,69 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.iotivity.cloud</groupId>
+  <artifactId>CloudStack</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  
+  <properties>
+               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+       </properties>
+       
+  <dependencies>
+               <dependency>
+                       <groupId>org.apache.maven.plugins</groupId>
+                       <artifactId>maven-resources-plugin</artifactId>
+                       <version>2.4.3</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.maven.plugins</groupId>
+                       <artifactId>maven-compiler-plugin</artifactId>
+                       <version>3.1</version>
+               </dependency>
+               <dependency>
+                       <groupId>io.netty</groupId>
+                       <artifactId>netty-all</artifactId>
+                       <version>4.0.29.Final</version>
+               </dependency>
+               <dependency>
+                       <groupId>commons-codec</groupId>
+                       <artifactId>commons-codec</artifactId>
+                       <version>1.9</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.json</groupId>
+                       <artifactId>json</artifactId>
+                       <version>20140107</version>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <version>4.12</version>
+               </dependency>
+               <dependency>
+               <groupId>com.fasterxml.jackson.core</groupId>
+               <artifactId>jackson-databind</artifactId>
+               <version>2.4.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>com.fasterxml.jackson.dataformat</groupId>
+                       <artifactId>jackson-dataformat-cbor</artifactId>
+                       <version>2.4.0</version>
+               </dependency>
+       </dependencies>
+       
+  <build>
+               <plugins>
+                       <plugin>
+                               <inherited>true</inherited>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <configuration>
+                                       <source>1.7</source>
+                                       <target>1.7</target>
+                                       <encoding>UTF-8</encoding>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+  
+</project>
\ No newline at end of file
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/CoapClient.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/CoapClient.java
new file mode 100644 (file)
index 0000000..ddd5d37
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.iotivity.cloud.base.protocols.coap.CoapDecoder;
+import org.iotivity.cloud.base.protocols.coap.CoapEncoder;
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.util.concurrent.GenericFutureListener;
+
+public class CoapClient {
+
+    private static class CoAPClientInitializer
+            extends ChannelInitializer<SocketChannel> {
+
+        private List<ChannelHandler> additionalHandlers = new ArrayList<ChannelHandler>();
+
+        public CoAPClientInitializer() {
+        }
+
+        public void addHandler(ChannelHandler handler) {
+            additionalHandlers.add(handler);
+        }
+
+        @Override
+        public void initChannel(SocketChannel ch) {
+            ChannelPipeline p = ch.pipeline();
+            /*
+             * if (sslCtx != null) { p.addLast(sslCtx.newHandler(ch.alloc())); }
+             */
+            p.addLast(new CoapDecoder());
+            p.addLast(new CoapEncoder());
+            for (ChannelHandler handler : additionalHandlers) {
+                p.addLast(handler);
+            }
+        }
+    }
+
+    private ChannelFuture channelFuture;
+
+    CoAPClientInitializer initializer = new CoAPClientInitializer();
+
+    public void addHandler(ChannelHandler handler) {
+        initializer.addHandler(handler);
+    }
+
+    public void startClient(final InetSocketAddress inetSocketAddress)
+            throws InterruptedException {
+        // Create bootstrap
+
+        EventLoopGroup bossGroup = new NioEventLoopGroup();
+        // bossGroup = new
+        // EpollEventLoopGroup(Runtime.getRuntime().availableProcessors() * 2);
+
+        try {
+            Bootstrap b = new Bootstrap();
+            b.group(bossGroup);
+            b.channel(NioSocketChannel.class);
+            b.option(ChannelOption.TCP_NODELAY, true);
+            b.option(ChannelOption.SO_KEEPALIVE, true);
+            b.option(ChannelOption.SO_REUSEADDR, true);
+
+            b.handler(initializer);
+
+            channelFuture = b.connect(inetSocketAddress).sync();
+
+            channelFuture
+                    .addListener(new GenericFutureListener<ChannelFuture>() {
+                        @Override
+                        public void operationComplete(ChannelFuture future)
+                                throws Exception {
+                            System.out.println(
+                                    "Connection status of TCP CoAP CLIENT  : "
+                                            + future.isSuccess());
+                        }
+                    });
+        } finally {
+        }
+    }
+
+    public ChannelFuture getChannelFuture() {
+        return channelFuture;
+    }
+
+    public void sendRequest(CoapRequest request) {
+        channelFuture.channel().writeAndFlush(request);
+    }
+
+    /**
+     * stop connection
+     */
+    public void stopClient() {
+
+        try {
+            if (channelFuture != null) {
+                channelFuture.channel().disconnect().sync().addListener(
+                        new GenericFutureListener<ChannelFuture>() {
+
+                            public void operationComplete(ChannelFuture future)
+                                    throws Exception {
+                                System.out.println(
+                                        "DisConnection status of TCP CoAP CLIENT : "
+                                                + future.isSuccess());
+                            }
+                        });
+            }
+        } catch (InterruptedException e1) {
+            e1.printStackTrace();
+        }
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/CoapServer.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/CoapServer.java
new file mode 100644 (file)
index 0000000..741c8ce
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base;
+
+import java.net.InetSocketAddress;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.net.ssl.SSLException;
+
+import org.iotivity.cloud.base.protocols.coap.CoapDecoder;
+import org.iotivity.cloud.base.protocols.coap.CoapEncoder;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+import io.netty.util.concurrent.GenericFutureListener;
+
+public class CoapServer {
+
+    private static class CoAPServerInitializer
+            extends ChannelInitializer<SocketChannel> {
+
+        private List<ChannelHandler> additionalHandlers = new ArrayList<ChannelHandler>();
+
+        public CoAPServerInitializer() {
+        }
+
+        public void addHandler(ChannelHandler handler) {
+            additionalHandlers.add(handler);
+        }
+
+        @Override
+        public void initChannel(SocketChannel ch) {
+            ChannelPipeline p = ch.pipeline();
+            /*
+             * if (sslCtx != null) { p.addLast(sslCtx.newHandler(ch.alloc())); }
+             */
+            p.addLast(new CoapDecoder());
+            p.addLast(new CoapEncoder());
+            for (ChannelHandler handler : additionalHandlers) {
+                p.addLast(handler);
+            }
+        }
+    }
+
+    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
+
+    EventLoopGroup workerGroup = new NioEventLoopGroup();
+
+    CoAPServerInitializer initializer = new CoAPServerInitializer();
+
+    public void addHandler(ChannelHandler handler) {
+        initializer.addHandler(handler);
+    }
+
+    public void startServer(InetSocketAddress inetSocketAddress)
+            throws CertificateException, SSLException, InterruptedException {
+
+        try {
+            ServerBootstrap b = new ServerBootstrap();
+            b.group(bossGroup, workerGroup);
+            b.channel(NioServerSocketChannel.class);
+            b.option(ChannelOption.TCP_NODELAY, true);
+            b.option(ChannelOption.SO_KEEPALIVE, true);
+            b.handler(new LoggingHandler(LogLevel.INFO));
+
+            b.childHandler(initializer);
+
+            ChannelFuture ch = b.bind(inetSocketAddress).sync();
+            ch.addListener(new GenericFutureListener<ChannelFuture>() {
+
+                @Override
+                public void operationComplete(ChannelFuture future)
+                        throws Exception {
+                    // TODO Auto-generated method stub
+                    System.out
+                            .println("Connection status of TCP CoAP SERVER  : "
+                                    + future.isSuccess());
+                }
+
+            });
+        } finally {
+        }
+
+    }
+
+    public void stopServer() {
+        // shut down all event loops
+        if (bossGroup != null) {
+            bossGroup.shutdownGracefully();
+
+            try {
+                bossGroup.terminationFuture().sync();
+            } catch (InterruptedException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+
+        if (workerGroup != null) {
+            workerGroup.shutdownGracefully();
+
+            try {
+                workerGroup.terminationFuture().sync();
+            } catch (InterruptedException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+    }
+
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/HttpClient.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/HttpClient.java
new file mode 100644 (file)
index 0000000..e1a2466
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.net.ssl.SSLException;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.ClientCookieEncoder;
+import io.netty.handler.codec.http.DefaultCookie;
+import io.netty.handler.codec.http.DefaultFullHttpRequest;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpContent;
+import io.netty.handler.codec.http.HttpContentDecompressor;
+import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpObject;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.codec.http.LastHttpContent;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import io.netty.util.CharsetUtil;
+
+public class HttpClient {
+
+    private static class HttpClientInitializer
+            extends ChannelInitializer<SocketChannel> {
+
+        public static class HttpSnoopClientHandler
+                extends SimpleChannelInboundHandler<HttpObject> {
+
+            @Override
+            public void channelRead0(ChannelHandlerContext ctx,
+                    HttpObject msg) {
+                if (msg instanceof HttpResponse) {
+                    HttpResponse response = (HttpResponse) msg;
+
+                    System.err.println("STATUS: " + response.getStatus());
+                    System.err.println(
+                            "VERSION: " + response.getProtocolVersion());
+                    System.err.println();
+
+                    if (!response.headers().isEmpty()) {
+                        for (String name : response.headers().names()) {
+                            for (String value : response.headers()
+                                    .getAll(name)) {
+                                System.err.println(
+                                        "HEADER: " + name + " = " + value);
+                            }
+                        }
+                        System.err.println();
+                    }
+
+                    if (HttpHeaders.isTransferEncodingChunked(response)) {
+                        System.err.println("CHUNKED CONTENT {");
+                    } else {
+                        System.err.println("CONTENT {");
+                    }
+                }
+                if (msg instanceof HttpContent) {
+                    HttpContent content = (HttpContent) msg;
+
+                    System.err.print(
+                            content.content().toString(CharsetUtil.UTF_8));
+                    System.err.flush();
+
+                    if (content instanceof LastHttpContent) {
+                        System.err.println("} END OF CONTENT");
+                        ctx.close();
+                    }
+                }
+            }
+
+            @Override
+            public void exceptionCaught(ChannelHandlerContext ctx,
+                    Throwable cause) {
+                cause.printStackTrace();
+                ctx.close();
+            }
+        }
+
+        private final SslContext sslCtx;
+
+        public HttpClientInitializer(SslContext sslCtx) {
+            this.sslCtx = sslCtx;
+        }
+
+        @Override
+        public void initChannel(SocketChannel ch) {
+            ChannelPipeline p = ch.pipeline();
+
+            // Enable HTTPS if necessary.
+            if (sslCtx != null) {
+                p.addLast(sslCtx.newHandler(ch.alloc()));
+            }
+
+            p.addLast(new HttpClientCodec());
+
+            // Remove the following line if you don't want automatic content
+            // decompression.
+            p.addLast(new HttpContentDecompressor());
+
+            // Uncomment the following line if you don't want to handle
+            // HttpContents.
+            // p.addLast(new HttpObjectAggregator(1048576));
+
+            p.addLast(new HttpSnoopClientHandler());
+        }
+    }
+
+    public void connect(String strUrl)
+            throws URISyntaxException, InterruptedException, SSLException {
+        URI uri = new URI(strUrl);
+
+        String scheme = uri.getScheme() == null ? "http" : uri.getScheme();
+        String host = uri.getHost() == null ? "127.0.0.1" : uri.getHost();
+
+        int port = uri.getPort();
+
+        if (port == -1) {
+            if ("http".equalsIgnoreCase(scheme)) {
+                port = 80;
+            } else if ("https".equalsIgnoreCase(scheme)) {
+                port = 443;
+            }
+        }
+
+        if (!"http".equalsIgnoreCase(scheme)
+                && !"https".equalsIgnoreCase(scheme)) {
+            return;
+        }
+
+        final boolean ssl = "https".equalsIgnoreCase(scheme);
+        final SslContext sslCtx;
+
+        if (ssl) {
+            sslCtx = SslContextBuilder.forClient()
+                    .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
+        } else {
+            sslCtx = null;
+        }
+
+        EventLoopGroup group = new NioEventLoopGroup();
+
+        try {
+            Bootstrap b = new Bootstrap();
+            b.group(group);
+            b.channel(NioSocketChannel.class);
+            b.handler(new HttpClientInitializer(sslCtx));
+
+            Channel ch = b.connect(host, port).sync().channel();
+
+            HttpRequest request = new DefaultFullHttpRequest(
+                    HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath());
+            request.headers().set(HttpHeaders.Names.HOST, host);
+            request.headers().set(HttpHeaders.Names.CONNECTION,
+                    HttpHeaders.Values.CLOSE);
+            request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING,
+                    HttpHeaders.Values.GZIP);
+
+            request.headers().set(HttpHeaders.Names.COOKIE,
+                    ClientCookieEncoder.encode(
+                            new DefaultCookie("my-cookie", "foo"),
+                            new DefaultCookie("another-cookie", "bar")));
+
+            ch.writeAndFlush(request);
+
+            ch.closeFuture().sync();
+        } finally {
+            group.shutdownGracefully();
+        }
+    }
+
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/HttpServer.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/HttpServer.java
new file mode 100644 (file)
index 0000000..7183f6e
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base;
+
+import java.net.InetSocketAddress;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.net.ssl.SSLException;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+import io.netty.util.concurrent.GenericFutureListener;
+
+public class HttpServer {
+
+    private static class HttpServerInitializer
+            extends ChannelInitializer<SocketChannel> {
+
+        private List<ChannelHandler> additionalHandlers = new ArrayList<ChannelHandler>();
+
+        public HttpServerInitializer() {
+        }
+
+        public void addHandler(ChannelHandler handler) {
+            additionalHandlers.add(handler);
+        }
+
+        @Override
+        public void initChannel(SocketChannel ch) {
+            ChannelPipeline p = ch.pipeline();
+            /*
+             * if (sslCtx != null) { p.addLast(sslCtx.newHandler(ch.alloc())); }
+             */
+            p.addLast(new HttpRequestDecoder());
+            // Uncomment the following line if you don't want to handle
+            // HttpChunks.
+            // p.addLast(new HttpObjectAggregator(1048576));
+            p.addLast(new HttpResponseEncoder());
+            // Remove the following line if you don't want automatic content
+            // compression.
+            // p.addLast(new HttpContentCompressor());
+            for (ChannelHandler handler : additionalHandlers) {
+                p.addLast(handler);
+            }
+        }
+
+    }
+
+    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
+
+    EventLoopGroup workerGroup = new NioEventLoopGroup();
+
+    HttpServerInitializer initializer = new HttpServerInitializer();
+
+    public void addHandler(ChannelHandler handler) {
+        initializer.addHandler(handler);
+    }
+
+    public void startServer(InetSocketAddress inetSocketAddress)
+            throws CertificateException, SSLException, InterruptedException {
+
+        try {
+            ServerBootstrap b = new ServerBootstrap();
+            b.group(bossGroup, workerGroup);
+            b.channel(NioServerSocketChannel.class);
+            b.handler(new LoggingHandler(LogLevel.INFO));
+
+            b.childHandler(initializer);
+
+            ChannelFuture ch = b.bind(inetSocketAddress).sync();
+            ch.addListener(new GenericFutureListener<ChannelFuture>() {
+
+                @Override
+                public void operationComplete(ChannelFuture future)
+                        throws Exception {
+                    // TODO Auto-generated method stub
+                    System.out
+                            .println("Connection status of TCP Http SERVER  : "
+                                    + future.isSuccess());
+                }
+
+            });
+        } finally {
+        }
+
+    }
+
+    public void stopServer() {
+        // shut down all event loops
+        if (bossGroup != null) {
+            bossGroup.shutdownGracefully();
+
+            try {
+                bossGroup.terminationFuture().sync();
+            } catch (InterruptedException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+
+        if (workerGroup != null) {
+            workerGroup.shutdownGracefully();
+
+            try {
+                workerGroup.terminationFuture().sync();
+            } catch (InterruptedException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+    }
+
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/Resource.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/Resource.java
new file mode 100644 (file)
index 0000000..cdf249c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base;
+
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+
+import io.netty.channel.ChannelHandlerContext;
+
+public abstract class Resource {
+
+    public Resource() {
+    }
+
+    private String uri;
+    private String type;
+    private String rif; // resource interface
+
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getRif() {
+        return rif;
+    }
+
+    public void setRif(String rif) {
+        this.rif = rif;
+    }
+
+    public abstract void onRequestReceived(ChannelHandlerContext ctx,
+            CoapRequest request);
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/ResourceManager.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/ResourceManager.java
new file mode 100644 (file)
index 0000000..b33ba24
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base;
+
+import java.util.ArrayList;
+
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+import org.iotivity.cloud.util.Logger;
+
+import io.netty.channel.ChannelHandler.Sharable;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+
+@Sharable
+public class ResourceManager extends SimpleChannelInboundHandler<CoapRequest> {
+
+    private ArrayList<Resource> resources      = new ArrayList<Resource>();
+    SessionManager              sessionManager = null;
+
+    public ResourceManager() {
+
+    }
+
+    public ResourceManager(SessionManager sessionManager) {
+        this.sessionManager = sessionManager;
+    }
+
+    @Override
+    public void channelReadComplete(ChannelHandlerContext ctx) {
+        ctx.flush();
+    }
+
+    @Override
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+        Logger.d("Channel Inactive");
+        sessionManager.removeSessionByChannel(ctx);
+        super.channelInactive(ctx);
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+
+        cause.printStackTrace();
+        ctx.close();
+    }
+
+    @Override
+    public void channelRead0(ChannelHandlerContext ctx, CoapRequest request)
+            throws Exception {
+
+        Resource res = queryResourceHandler(request.getUriPath());
+
+        if (res != null) {
+            res.onRequestReceived(ctx, request);
+        }
+    }
+
+    private Resource queryResourceHandler(String query_uri) {
+
+        Resource res = null;
+
+        for (Resource r : resources) {
+
+            String uri = r.getUri();
+            if (uri.contains(query_uri)) {
+                res = r;
+                break;
+            }
+        }
+
+        return res;
+    }
+
+    public void registerResource(Resource res) {
+
+        synchronized (this) {
+            resources.add(res);
+        }
+    }
+
+    public void unregisterResource(Resource res) {
+
+        synchronized (this) {
+            resources.remove(res);
+        }
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/SessionManager.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/SessionManager.java
new file mode 100644 (file)
index 0000000..6b0ef5d
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import org.iotivity.cloud.util.Logger;
+
+import io.netty.channel.ChannelHandlerContext;
+
+public class SessionManager {
+
+    HashMap<String, ChannelHandlerContext> sessions = new HashMap<String, ChannelHandlerContext>();
+
+    public void addSession(String did, ChannelHandlerContext ctx) {
+        synchronized (sessions) {
+            sessions.put(did, ctx);
+        }
+    }
+
+    public void removeSession(String did) {
+
+        synchronized (sessions) {
+            sessions.remove(did);
+        }
+    }
+
+    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;
+                }
+            }
+        }
+    }
+
+    public ChannelHandlerContext querySession(String did) {
+        ChannelHandlerContext ctx = null;
+
+        synchronized (sessions) {
+            ctx = sessions.get(did);
+        }
+
+        return ctx;
+    }
+
+    public boolean isThereCtx(ChannelHandlerContext ctx) {
+
+        synchronized (sessions) {
+            return sessions.containsValue(ctx);
+        }
+    }
+
+    public boolean isThereCtxChannel(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;
+                }
+            }
+            return false;
+        }
+    }
+
+    public List<String> getSessions() {
+        return new ArrayList<String>(sessions.keySet());
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapDecoder.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapDecoder.java
new file mode 100644 (file)
index 0000000..46d618f
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base.protocols.coap;
+
+import java.util.List;
+
+import org.iotivity.cloud.base.protocols.coap.enums.CoapMethod;
+import org.iotivity.cloud.base.protocols.coap.enums.CoapStatus;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
+public class CoapDecoder extends ByteToMessageDecoder {
+
+    private enum ParsingState {
+        SHIM_HEADER, OPTION_PAYLOAD_LENGTH, CODE_TOKEN_OPTION, PAYLOAD, FINISH
+    }
+
+    private ParsingState nextState           = ParsingState.SHIM_HEADER;
+    private int          bufferToRead        = 1;
+    private int          tokenLength         = 0;
+    private int          optionPayloadLength = 0;
+    private CoapMessage  partialMsg          = null;
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, ByteBuf in,
+            List<Object> out) throws Exception {
+
+        while (in.isReadable(bufferToRead)) {
+
+            switch (nextState) {
+                case SHIM_HEADER:
+                    int shimHeader = in.readByte();
+                    bufferToRead = (shimHeader >>> 4) & 0x0F;
+                    tokenLength = (shimHeader) & 0x0F;
+                    switch (bufferToRead) {
+                        case 13:
+                            bufferToRead = 1;
+                            nextState = ParsingState.OPTION_PAYLOAD_LENGTH;
+                            break;
+                        case 14:
+                            bufferToRead = 2;
+                            nextState = ParsingState.OPTION_PAYLOAD_LENGTH;
+                            break;
+                        case 15:
+                            bufferToRead = 4;
+                            nextState = ParsingState.OPTION_PAYLOAD_LENGTH;
+                            break;
+                        default:
+                            optionPayloadLength = bufferToRead;
+                            bufferToRead += 1 + tokenLength; // code + tkl
+                            nextState = ParsingState.CODE_TOKEN_OPTION;
+                            break;
+                    }
+                    break;
+
+                case OPTION_PAYLOAD_LENGTH:
+                    switch (bufferToRead) {
+                        case 1:
+                            optionPayloadLength = 13 + (in.readByte() & 0xFF);
+                            break;
+
+                        case 2:
+                            optionPayloadLength = 269
+                                    + (((in.readByte() & 0xFF) << 8)
+                                            + (in.readByte() & 0xFF));
+                            break;
+
+                        case 4:
+                            optionPayloadLength = 65805
+                                    + (((in.readByte() & 0xFF) << 24)
+                                            + ((in.readByte() & 0xFF) << 16)
+                                            + ((in.readByte() & 0xFF) << 8)
+                                            + (in.readByte() & 0xFF));
+                            break;
+                    }
+                    nextState = ParsingState.CODE_TOKEN_OPTION;
+                    bufferToRead = 1 + tokenLength + optionPayloadLength; // code
+                                                                          // +
+                                                                          // tkl
+                    break;
+
+                case CODE_TOKEN_OPTION:
+                    int code = in.readByte() & 0xFF;
+
+                    if (code <= 31) {
+                        partialMsg = new CoapRequest(CoapMethod.valueOf(code));
+                    } else {
+                        partialMsg = new CoapResponse(CoapStatus.valueOf(code));
+                    }
+
+                    if (tokenLength > 0) {
+                        byte[] token = new byte[tokenLength];
+                        in.readBytes(token);
+                        partialMsg.setToken(token);
+                    }
+
+                    if (optionPayloadLength > 0) {
+                        int optionLen = parseOptions(partialMsg, in,
+                                optionPayloadLength);
+                        if (optionPayloadLength > optionLen) {
+                            nextState = ParsingState.PAYLOAD;
+                            bufferToRead = optionPayloadLength - optionLen;
+                            continue;
+                        }
+                    }
+
+                    nextState = ParsingState.FINISH;
+                    bufferToRead = 0;
+
+                    break;
+
+                case PAYLOAD:
+                    byte[] payload = new byte[bufferToRead];
+                    in.readBytes(payload);
+                    partialMsg.setPayload(payload);
+                    nextState = ParsingState.FINISH;
+                    bufferToRead = 0;
+                    break;
+
+                case FINISH:
+                    nextState = ParsingState.SHIM_HEADER;
+                    bufferToRead = 1;
+                    out.add(partialMsg);
+                    break;
+
+                default:
+                    break;
+            }
+        }
+
+        in.discardReadBytes();
+    }
+
+    private int parseOptions(CoapMessage coapMessage, ByteBuf byteBuf,
+            int maxLength) {
+
+        int preOptionNum = 0;
+
+        int startPos = byteBuf.readerIndex();
+
+        int firstByte = byteBuf.readByte() & 0xFF;
+
+        while (firstByte != 0xFF && maxLength > 0) {
+            int optionDelta = (firstByte & 0xF0) >>> 4;
+            int optionLength = firstByte & 0x0F;
+
+            if (optionDelta == 13) {
+                optionDelta = 13 + byteBuf.readByte() & 0xFF;
+            } else if (optionDelta == 14) {
+                optionDelta = 269 + ((byteBuf.readByte() & 0xFF) << 8)
+                        + (byteBuf.readByte() & 0xFF);
+            }
+
+            if (optionLength == 13) {
+                optionLength = 13 + byteBuf.readByte() & 0xFF;
+            } else if (optionLength == 14) {
+                optionLength = 269 + ((byteBuf.readByte() & 0xFF) << 8)
+                        + (byteBuf.readByte() & 0xFF);
+            }
+
+            int curOptionNum = preOptionNum + optionDelta;
+            byte[] optionValue = new byte[optionLength];
+            byteBuf.readBytes(optionValue);
+
+            coapMessage.addOption(curOptionNum, optionValue);
+
+            preOptionNum = curOptionNum;
+            if (maxLength > byteBuf.readerIndex() - startPos) {
+                firstByte = byteBuf.readByte() & 0xFF;
+            } else {
+                break;
+            }
+        }
+
+        /// return option length
+        return byteBuf.readerIndex() - startPos;
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapEncoder.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapEncoder.java
new file mode 100644 (file)
index 0000000..f047fd8
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base.protocols.coap;
+
+import java.util.List;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+
+public class CoapEncoder extends MessageToByteEncoder<CoapMessage> {
+
+    @Override
+    protected void encode(ChannelHandlerContext ctx, CoapMessage msg,
+            ByteBuf out) throws Exception {
+
+        CoapMessage coapMessage = (CoapMessage) msg;
+
+        ByteBuf optBuf = Unpooled.directBuffer();
+
+        /**
+         * encode options
+         */
+        encodeOptions(optBuf, coapMessage);
+        long length = optBuf.readableBytes();
+
+        if (coapMessage.getPayloadSize() > 0) {
+            // + 1 means 8bits delimiter
+            length += 1 + coapMessage.getPayloadSize();
+        }
+
+        calcShimHeader(coapMessage, out, length);
+
+        out.writeByte(coapMessage.getCode());
+
+        if (coapMessage.getTokenLength() > 0) {
+            out.writeBytes(coapMessage.getToken());
+        }
+
+        // Write option
+        if (optBuf.readableBytes() > 0) {
+            out.writeBytes(optBuf);
+        }
+
+        optBuf.release();
+
+        if (coapMessage.getPayloadSize() > 0) {
+            out.writeByte(255);
+            out.writeBytes(coapMessage.getPayload());
+        }
+    }
+
+    private void calcShimHeader(CoapMessage coapMessage, ByteBuf byteBuf,
+            long length) {
+        if (length < 13) {
+            byteBuf.writeByte(((int) length & 0x0F) << 4
+                    | (coapMessage.getTokenLength() & 0x0F));
+        } else if (length < 269) {
+            byteBuf.writeShort((13 & 0x0F) << 12
+                    | (coapMessage.getTokenLength() & 0x0F) << 8
+                    | (((int) length - 13) & 0xFF));
+        } else if (length < 65805) {
+            byteBuf.writeByte(
+                    (14 & 0x0F) << 4 | (coapMessage.getTokenLength() & 0x0F));
+            byteBuf.writeShort(((int) length - 269) & 0xFFFF);
+        } else if (length < Integer.MAX_VALUE * 2) {
+            byteBuf.writeByte(
+                    (15 & 0x0F) << 4 | (coapMessage.getTokenLength() & 0x0F));
+            byteBuf.writeLong((length - 65805) & 0xFFFFFFFF);
+        } else {
+            throw new IllegalArgumentException(
+                    "Length must be less than 4GB " + length);
+        }
+    }
+
+    private void encodeOptions(ByteBuf byteBuf, CoapMessage coapMessage)
+            throws Exception {
+        int preOptionNum = 0;
+
+        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);
+                    preOptionNum = i;
+                }
+            }
+        }
+    }
+
+    private void writeOption(int optionDelta, int optionLength, ByteBuf byteBuf,
+            byte[] value) {
+
+        if (optionDelta < 13) {
+            if (optionLength < 13) {
+                byteBuf.writeByte(
+                        ((optionDelta & 0xFF) << 4) | (optionLength & 0xFF));
+            } else if (optionLength < 269) {
+                byteBuf.writeByte(((optionDelta << 4) & 0xFF) | (13 & 0xFF));
+                byteBuf.writeByte((optionLength - 13) & 0xFF);
+            } else {
+                byteBuf.writeByte(((optionDelta << 4) & 0xFF) | (14 & 0xFF));
+                byteBuf.writeByte(((optionLength - 269) & 0xFF00) >>> 8);
+                byteBuf.writeByte((optionLength - 269) & 0xFF);
+            }
+        }
+
+        else if (optionDelta < 269) {
+            if (optionLength < 13) {
+                byteBuf.writeByte(((13 & 0xFF) << 4) | (optionLength & 0xFF));
+                byteBuf.writeByte((optionDelta - 13) & 0xFF);
+            } else if (optionLength < 269) {
+                byteBuf.writeByte(((13 & 0xFF) << 4) | (13 & 0xFF));
+                byteBuf.writeByte((optionDelta - 13) & 0xFF);
+                byteBuf.writeByte((optionLength - 13) & 0xFF);
+            } else {
+                byteBuf.writeByte((13 & 0xFF) << 4 | (14 & 0xFF));
+                byteBuf.writeByte((optionDelta - 13) & 0xFF);
+                byteBuf.writeByte(((optionLength - 269) & 0xFF00) >>> 8);
+                byteBuf.writeByte((optionLength - 269) & 0xFF);
+            }
+        }
+
+        else if (optionDelta < 65805) {
+
+            if (optionLength < 13) {
+                byteBuf.writeByte(((14 & 0xFF) << 4) | (optionLength & 0xFF));
+                byteBuf.writeByte(((optionDelta - 269) & 0xFF00) >>> 8);
+                byteBuf.writeByte((optionDelta - 269) & 0xFF);
+            }
+
+            else if (optionLength < 269) {
+                byteBuf.writeByte(((14 & 0xFF) << 4) | (13 & 0xFF));
+                byteBuf.writeByte(((optionDelta - 269) & 0xFF00) >>> 8);
+                byteBuf.writeByte((optionDelta - 269) & 0xFF);
+                byteBuf.writeByte((optionLength - 13) & 0xFF);
+            }
+
+            else {
+                byteBuf.writeByte(((14 & 0xFF) << 4) | (14 & 0xFF));
+                byteBuf.writeByte(((optionDelta - 269) & 0xFF00) >>> 8);
+                byteBuf.writeByte((optionDelta - 269) & 0xFF);
+                byteBuf.writeByte(((optionLength - 269) & 0xFF00) >>> 8);
+                byteBuf.writeByte((optionLength - 269) & 0xFF);
+            }
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported option delta " + optionDelta);
+        }
+
+        if (optionLength > 0) {
+            byteBuf.writeBytes(value);
+        }
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapMessage.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapMessage.java
new file mode 100644 (file)
index 0000000..57382e2
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base.protocols.coap;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import org.iotivity.cloud.base.protocols.coap.enums.CoapOption;
+import org.iotivity.cloud.util.Cbor;
+import org.iotivity.cloud.util.Logger;
+
+public class CoapMessage {
+
+    private int    tokenLength = 0;
+    protected int  code        = 0;
+    private byte[] token       = null;
+
+    private byte[] payload = null;
+
+    // Option fields
+    protected List<byte[]> if_match       = null;
+    protected byte[]       uri_host       = null;
+    protected List<byte[]> etag           = null;
+    protected boolean      if_none_match  = false;
+    protected byte[]       uri_port       = null;
+    protected List<byte[]> location_path  = null;
+    protected List<byte[]> uri_path       = null;
+    protected byte[]       content_format = null;
+    protected byte[]       max_age        = null;
+    protected List<byte[]> uri_query      = null;
+    protected byte[]       accept         = null;
+    protected List<byte[]> location_query = null;
+    protected byte[]       proxy_uri      = null;
+    protected byte[]       proxy_scheme   = null;
+    protected byte[]       size1          = null;
+    protected boolean      observe        = false;
+
+    public CoapMessage() {
+    }
+
+    public int getTokenLength() {
+        return this.tokenLength;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public byte[] getToken() {
+        return token;
+    }
+
+    public void setToken(byte[] token) {
+        this.token = token;
+        this.tokenLength = token.length;
+    }
+
+    public int getPayloadSize() {
+        return payload == null ? 0 : payload.length;
+    }
+
+    public byte[] getPayload() {
+        return payload;
+    }
+
+    public void setPayload(byte[] payload) {
+        this.payload = payload;
+    }
+
+    public void addOption(int optnum, byte[] value) {
+        switch (optnum) {
+            // IF_MATCH
+            case 1:
+                if (if_match == null) {
+                    if_match = new ArrayList<byte[]>();
+                }
+                if_match.add(value);
+                break;
+
+            // URI_HOST
+            case 3:
+                uri_host = value;
+                break;
+
+            // ETAG
+            case 4:
+                if (etag == null) {
+                    etag = new ArrayList<byte[]>();
+                }
+                etag.add(value);
+                break;
+
+            // IF_NONE_MATCH
+            case 5:
+                if_none_match = true;
+                break;
+
+            // URI_PORT
+            case 7:
+                uri_port = value;
+                break;
+
+            // LOCATION_PATH
+            case 8:
+                if (location_path == null) {
+                    location_path = new ArrayList<byte[]>();
+                }
+                location_path.add(value);
+                break;
+
+            // URI_PATH
+            case 11:
+                if (uri_path == null) {
+                    uri_path = new ArrayList<byte[]>();
+                }
+                uri_path.add(value);
+                break;
+
+            // CONTENT_FORMAT
+            case 12:
+                content_format = value;
+                break;
+
+            // MAX_AGE
+            case 14:
+                max_age = value;
+                break;
+
+            // URI_QUERY
+            case 15:
+                if (uri_query == null) {
+                    uri_query = new ArrayList<byte[]>();
+                }
+                uri_query.add(value);
+                break;
+
+            // ACCEPT
+            case 17:
+                accept = value;
+                break;
+
+            // LOCATION_QUERY
+            case 20:
+                if (location_query == null) {
+                    location_query = new ArrayList<byte[]>();
+                }
+                location_query.add(value);
+                break;
+
+            // PROXY_URI
+            case 35:
+                proxy_uri = value;
+                break;
+
+            // PROXY_SCHEME
+            case 39:
+                proxy_scheme = value;
+                break;
+
+            // SIZE1
+            case 60:
+                size1 = value;
+                break;
+
+            // OBSERVE
+            case 6:
+                observe = true;
+                break;
+        }
+    }
+
+    public List<byte[]> getOption(int optnum) {
+        switch (optnum) {
+            // IF_MATCH
+            case 1:
+                return if_match;
+
+            // URI_HOST
+            case 3:
+                return uri_host != null ? Arrays.asList(uri_host) : null;
+
+            // ETAG
+            case 4:
+                return etag;
+
+            // IF_NONE_MATCH
+            case 5:
+                return if_none_match == true ? new ArrayList<byte[]>() : null;
+
+            // URI_PORT
+            case 7:
+                return uri_port != null ? Arrays.asList(uri_port) : null;
+
+            // LOCATION_PATH
+            case 8:
+                return location_path;
+
+            // URI_PATH
+            case 11:
+                return uri_path;
+
+            // CONTENT_FORMAT
+            case 12:
+                return content_format != null ? Arrays.asList(content_format)
+                        : null;
+
+            // MAX_AGE
+            case 14:
+                return max_age != null ? Arrays.asList(max_age) : null;
+
+            // URI_QUERY
+            case 15:
+                return uri_query;
+
+            // ACCEPT
+            case 17:
+                return accept != null ? Arrays.asList(content_format) : null;
+
+            // LOCATION_QUERY
+            case 20:
+                return location_query;
+
+            // PROXY_URI
+            case 35:
+                return proxy_uri != null ? Arrays.asList(proxy_uri) : null;
+
+            // PROXY_SCHEME
+            case 39:
+                return proxy_scheme != null ? Arrays.asList(proxy_scheme)
+                        : null;
+
+            // SIZE1
+            case 60:
+                return size1 != null ? Arrays.asList(size1) : null;
+
+            // OBSERVE
+            case 6:
+                return observe == true ? new ArrayList<byte[]>() : null;
+        }
+
+        return null;
+    }
+
+    public String getTokenString() {
+        StringBuffer strBuffer = new StringBuffer(token == null ? "null" : "");
+        if (token != null)
+            for (byte b : token)
+                strBuffer.append(String.format("%02x", b & 0xff)); // hexadecimal(16)
+        return strBuffer.toString();
+    }
+
+    public String getContentFormatString() {
+        List<byte[]> contentFormatList = getOption(
+                CoapOption.CONTENT_FORMAT.getvalue());
+        byte[] contentFormat = null;
+        if (contentFormatList != null && !contentFormatList.isEmpty())
+            contentFormat = contentFormatList.get(0);
+        StringBuffer strBuffer = new StringBuffer(
+                contentFormat == null ? "null" : "");
+        if (contentFormat != null)
+            for (byte b : contentFormat)
+                strBuffer.append(String.format("%02d", b & 0xff)); // decimal(10)
+        return strBuffer.toString();
+    }
+
+    public String getPayloadString() {
+        if (payload == null)
+            return "";
+        return new String(payload, Charset.forName("UTF-8"));
+    }
+
+    public String decodeDeviceId() {
+        Cbor<ArrayList<Object>> cbor = new Cbor<ArrayList<Object>>();
+        ArrayList<Object> decodedPayload = null;
+
+        if (payload == null) {
+            throw new IllegalArgumentException("payload is null");
+        }
+
+        else {
+            decodedPayload = cbor.parsePayloadFromCbor(payload,
+                    ArrayList.class);
+
+            HashMap<Object, Object> tags = (HashMap<Object, Object>) decodedPayload
+                    .get(0);
+
+            String deviceId = tags.get("di").toString();
+
+            if (deviceId == null) {
+                throw new IllegalArgumentException("deviceId is null");
+            }
+
+            Logger.i("deviceId : " + deviceId);
+
+            return deviceId;
+        }
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapRequest.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapRequest.java
new file mode 100644 (file)
index 0000000..35657a6
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base.protocols.coap;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.iotivity.cloud.base.protocols.coap.enums.CoapMethod;
+
+public class CoapRequest extends CoapMessage {
+    public CoapRequest(CoapMethod method) {
+        this.code = method.getCode();
+    }
+
+    public CoapMethod getRequestMethod() {
+        return CoapMethod.valueOf(code);
+    }
+
+    public void setUriPath(String path) {
+        if (uri_path == null) {
+            uri_path = new ArrayList<byte[]>();
+        }
+        clearUriPath();
+
+        String[] pathSegments = path.split("/");
+        for (String pathSegment : pathSegments) {
+            if (pathSegment.length() == 0)
+                continue;
+            uri_path.add(pathSegment.getBytes(StandardCharsets.UTF_8));
+        }
+    }
+
+    public String getUriPath() {
+        if (uri_path == null) {
+            return null;
+        }
+        StringBuilder path = new StringBuilder();
+        int nItem = uri_path.size();
+        for (byte[] pathSegment : uri_path) {
+            path.append(new String(pathSegment, StandardCharsets.UTF_8));
+            if (--nItem > 0) {
+                path.append('/');
+            }
+        }
+        return path.toString();
+    }
+
+    public List<String> getUriPathSegments() {
+        List<String> segments = new ArrayList<String>();
+        if (uri_path != null) {
+            for (byte[] pathSegment : uri_path) {
+                segments.add(new String(pathSegment, StandardCharsets.UTF_8));
+            }
+        }
+        return segments;
+    }
+
+    public void setUriQuery(String query) {
+        if (uri_query == null) {
+            uri_query = new ArrayList<byte[]>();
+        }
+        String[] querySegments = query.split("&");
+        for (String querySegment : querySegments) {
+            uri_query.add(querySegment.getBytes(StandardCharsets.UTF_8));
+        }
+    }
+
+    public String getUriQuery() {
+        if (uri_query == null) {
+            return null;
+        }
+        StringBuilder uriQuery = new StringBuilder();
+        int nItem = uri_query.size();
+        for (byte[] querySegment : uri_query) {
+            uriQuery.append(new String(querySegment, StandardCharsets.UTF_8));
+            if (--nItem > 0) {
+                uriQuery.append('&');
+            }
+        }
+        return uriQuery.toString();
+    }
+
+    public List<String> getUriQuerySegments() {
+        List<String> segments = new ArrayList<String>();
+        for (byte[] querySegment : uri_query) {
+            segments.add(new String(querySegment, StandardCharsets.UTF_8));
+        }
+        return segments;
+    }
+
+    public void clearUriPath() {
+        uri_path.clear();
+    }
+
+    public void setAccept(byte[] accepts) {
+        accept = accepts;
+    }
+}
\ No newline at end of file
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapResponse.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/CoapResponse.java
new file mode 100644 (file)
index 0000000..d4b07cb
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base.protocols.coap;
+
+import org.iotivity.cloud.base.protocols.coap.enums.CoapStatus;
+
+public class CoapResponse extends CoapMessage {
+    public CoapResponse(CoapStatus status) {
+        this.code = status.getCode();
+    }
+
+    public CoapStatus getResponseCode() {
+        return CoapStatus.valueOf(code);
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/enums/CoapMethod.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/enums/CoapMethod.java
new file mode 100644 (file)
index 0000000..90b99da
--- /dev/null
@@ -0,0 +1,33 @@
+package org.iotivity.cloud.base.protocols.coap.enums;
+
+public enum CoapMethod {
+    GET(1), POST(2), PUT(3), DELETE(4);
+
+    public static CoapMethod valueOf(int code) {
+        switch (code) {
+            case 1:
+                return CoapMethod.GET;
+
+            case 2:
+                return CoapMethod.POST;
+
+            case 3:
+                return CoapMethod.PUT;
+
+            case 4:
+                return CoapMethod.DELETE;
+        }
+
+        throw new IllegalArgumentException("Invalid Method value");
+    }
+
+    private final int code;
+
+    private CoapMethod(int code) {
+        this.code = code;
+    }
+
+    public int getCode() {
+        return code;
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/enums/CoapOption.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/enums/CoapOption.java
new file mode 100644 (file)
index 0000000..f8439c8
--- /dev/null
@@ -0,0 +1,73 @@
+package org.iotivity.cloud.base.protocols.coap.enums;
+
+public enum CoapOption {
+    IF_MATCH(1), URI_HOST(3), ETAG(4), IF_NONE_MATCH(5), URI_PORT(
+            7), LOCATION_PATH(8), URI_PATH(11), CONTENT_FORMAT(12), MAX_AGE(
+                    14), URI_QUERY(15), ACCEPT(17), LOCATION_QUERY(
+                            20), PROXY_URI(35), PROXY_SCHEME(39), SIZE1(
+                                    60), OBSERVE(6);
+
+    public static CoapOption valueOf(int option) {
+        switch (option) {
+            case 1:
+                return CoapOption.IF_MATCH;
+
+            case 3:
+                return CoapOption.URI_HOST;
+
+            case 4:
+                return CoapOption.ETAG;
+
+            case 5:
+                return CoapOption.IF_NONE_MATCH;
+
+            case 7:
+                return CoapOption.URI_PORT;
+
+            case 8:
+                return CoapOption.LOCATION_PATH;
+
+            case 11:
+                return CoapOption.URI_PATH;
+
+            case 12:
+                return CoapOption.CONTENT_FORMAT;
+
+            case 14:
+                return CoapOption.MAX_AGE;
+
+            case 15:
+                return CoapOption.URI_QUERY;
+
+            case 17:
+                return CoapOption.ACCEPT;
+
+            case 20:
+                return CoapOption.LOCATION_QUERY;
+
+            case 35:
+                return CoapOption.PROXY_URI;
+
+            case 39:
+                return CoapOption.PROXY_SCHEME;
+
+            case 60:
+                return CoapOption.SIZE1;
+
+            case 6:
+                return CoapOption.OBSERVE;
+        }
+
+        throw new IllegalArgumentException("Invalid option value");
+    }
+
+    private final int value;
+
+    private CoapOption(int value) {
+        this.value = value;
+    }
+
+    public int getvalue() {
+        return value;
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/enums/CoapStatus.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/coap/enums/CoapStatus.java
new file mode 100644 (file)
index 0000000..a687ad3
--- /dev/null
@@ -0,0 +1,97 @@
+package org.iotivity.cloud.base.protocols.coap.enums;
+
+public enum CoapStatus {
+    // Success 2.xx
+    CREATED(65), DELETED(66), VALID(67), CHANGED(68), CONTENT(69),
+    // Client Error 4.xx
+    BAD_REQUEST(128), UNAUTHORIZED(129), BAD_OPTION(130), FORBIDDEN(131),
+    //
+    NOT_FOUND(132), METHOD_NOT_ALLOWED(133), NOT_ACCEPTABLE(134),
+    //
+    PRECONDITION_FAILED(140), REQUEST_ENTITY_TOO_LARGE(141),
+    //
+    UNSUPPORTED_CONTENT_FORMAT(143),
+    // Server Error 5.xx
+    INTERNAL_SERVER_ERROR(160), NOT_IMPLEMENTED(161), BAD_GATEWAY(162),
+    //
+    SERVICE_UNAVAILABLE(163), GATEWAY_TIMEOUT(164), PROXY_NOT_SUPPORTED(165);
+
+    public static CoapStatus valueOf(int code) {
+        switch (code) {
+            case 65:
+                return CoapStatus.CREATED;
+
+            case 66:
+                return CoapStatus.DELETED;
+
+            case 67:
+                return CoapStatus.VALID;
+
+            case 68:
+                return CoapStatus.CHANGED;
+
+            case 69:
+                return CoapStatus.CONTENT;
+
+            case 128:
+                return CoapStatus.BAD_REQUEST;
+
+            case 129:
+                return CoapStatus.UNAUTHORIZED;
+
+            case 130:
+                return CoapStatus.BAD_OPTION;
+
+            case 131:
+                return CoapStatus.FORBIDDEN;
+
+            case 132:
+                return CoapStatus.NOT_FOUND;
+
+            case 133:
+                return CoapStatus.METHOD_NOT_ALLOWED;
+
+            case 134:
+                return CoapStatus.NOT_ACCEPTABLE;
+
+            case 140:
+                return CoapStatus.PRECONDITION_FAILED;
+
+            case 141:
+                return CoapStatus.REQUEST_ENTITY_TOO_LARGE;
+
+            case 143:
+                return CoapStatus.UNSUPPORTED_CONTENT_FORMAT;
+
+            case 160:
+                return CoapStatus.INTERNAL_SERVER_ERROR;
+
+            case 161:
+                return CoapStatus.NOT_IMPLEMENTED;
+
+            case 162:
+                return CoapStatus.BAD_GATEWAY;
+
+            case 163:
+                return CoapStatus.SERVICE_UNAVAILABLE;
+
+            case 164:
+                return CoapStatus.GATEWAY_TIMEOUT;
+
+            case 165:
+                return CoapStatus.PROXY_NOT_SUPPORTED;
+        }
+
+        throw new IllegalArgumentException("Invalid Status value");
+    }
+
+    private final int code;
+
+    private CoapStatus(int code) {
+        this.code = code;
+    }
+
+    public int getCode() {
+        return code;
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/proxy/CoapHttpProxyHandler.java b/cloud/stack/src/main/java/org/iotivity/cloud/base/protocols/proxy/CoapHttpProxyHandler.java
new file mode 100644 (file)
index 0000000..fda99c1
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base.protocols.proxy;
+
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.iotivity.cloud.base.SessionManager;
+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.util.Cbor;
+import org.iotivity.cloud.util.Logger;
+
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandler.Sharable;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.codec.http.QueryStringDecoder;
+import io.netty.util.AttributeKey;
+import io.netty.util.CharsetUtil;
+
+@Sharable
+public class CoapHttpProxyHandler extends ChannelDuplexHandler {
+
+    // Proxy converts http request to coaprequest and coapresponse to
+    // httpresponse
+    private SessionManager sessionManager = null;
+
+    private static final AttributeKey<ChannelHandlerContext> keyHttpCtx = AttributeKey
+            .newInstance("httpCtx");
+
+    public CoapHttpProxyHandler(SessionManager sessionManager) {
+        this.sessionManager = sessionManager;
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg)
+            throws Exception {
+
+        // in case of Receive Request from http
+        if (msg instanceof HttpRequest) {
+            // Check uri query param that contains coap device uuid
+            // then search those and create coapRequest and send
+            HttpRequest httpRequest = (HttpRequest) msg;
+            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(
+                    httpRequest.getUri());
+
+            List<String> didList = queryStringDecoder.parameters().get("di");
+
+            if (didList != null) {
+                ChannelHandlerContext coapClient = sessionManager
+                        .querySession(didList.get(0));
+
+                if (coapClient != null) {
+                    List<String> uriList = queryStringDecoder.parameters()
+                            .get("href");
+                    if (uriList != null) {
+                        coapClient.channel().attr(keyHttpCtx).set(ctx);
+                        coapClient.writeAndFlush(httpRequestToCoAPRequest(
+                                uriList.get(0), (HttpRequest) msg));
+
+                        return;
+                    }
+                } else {
+                    Logger.d("Unable to find session: " + didList.get(0));
+                }
+            }
+
+            // Prints available sessions to html
+
+            ctx.writeAndFlush(printsAvailableSessions())
+                    .addListener(ChannelFutureListener.CLOSE);
+            return;
+        }
+
+        if (msg instanceof CoapResponse) {
+            ctx.channel().attr(keyHttpCtx).get()
+                    .writeAndFlush(
+                            coapResponseToHttpResponse((CoapResponse) msg))
+                    .addListener(ChannelFutureListener.CLOSE);
+            return;
+        }
+
+        // Pass to upper-layer
+        super.channelRead(ctx, msg);
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+        cause.printStackTrace();
+        ctx.close();
+    }
+
+    HttpResponse printsAvailableSessions() {
+
+        StringBuilder strBuilder = new StringBuilder();
+        List<String> sessions = sessionManager.getSessions();
+
+        strBuilder.append("<html>");
+        strBuilder.append("<b>Available sessions</b><br>");
+
+        for (String session : sessions) {
+            strBuilder.append(session);
+            strBuilder.append("<br>");
+        }
+
+        strBuilder.append("</html>");
+
+        HttpResponse response = new DefaultFullHttpResponse(
+                HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
+                Unpooled.copiedBuffer(strBuilder.toString(),
+                        CharsetUtil.UTF_8));
+        response.headers().set(HttpHeaders.Names.CONTENT_TYPE,
+                "text/html; charset=UTF-8");
+
+        return response;
+    }
+
+    HttpResponse httpRequestToSendError() {
+        HttpResponse response = new DefaultFullHttpResponse(
+                HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND,
+                Unpooled.copiedBuffer(
+                        "Failure: " + HttpResponseStatus.NOT_FOUND + "\r\n",
+                        CharsetUtil.UTF_8));
+        response.headers().set(HttpHeaders.Names.CONTENT_TYPE,
+                "text/html; charset=UTF-8");
+
+        return response;
+    }
+
+    CoapRequest httpRequestToCoAPRequest(String uri, HttpRequest httpRequest) {
+        CoapRequest coapRequest;
+
+        // TODO: coapRequest converter required
+        // coapRequest.getOptions().setUriQuery();
+        if (httpRequest.getMethod() == HttpMethod.GET) {
+            coapRequest = new CoapRequest(CoapMethod.GET);
+        } else if (httpRequest.getMethod() == HttpMethod.PUT) {
+            coapRequest = new CoapRequest(CoapMethod.PUT);
+        } else if (httpRequest.getMethod() == HttpMethod.POST) {
+            coapRequest = new CoapRequest(CoapMethod.POST);
+        } else if (httpRequest.getMethod() == HttpMethod.DELETE) {
+            coapRequest = new CoapRequest(CoapMethod.DELETE);
+        } else {
+            throw new IllegalArgumentException();
+        }
+
+        coapRequest.setUriPath(uri);
+
+        return coapRequest;
+    }
+
+    HttpResponse coapResponseToHttpResponse(CoapResponse coapResponse) {
+
+        Cbor<HashMap<String, Object>> cbor = new Cbor<HashMap<String, Object>>();
+
+        HashMap<String, Object> rep = cbor
+                .parsePayloadFromCbor(coapResponse.getPayload(), HashMap.class);
+
+        StringBuilder strBuilder = new StringBuilder();
+
+        for (Entry<String, Object> entry : rep.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue().toString();
+            strBuilder.append("Key: " + key + " Value: " + value + "<br>");
+        }
+
+        HttpResponse httpResponse = new DefaultFullHttpResponse(
+                HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
+                Unpooled.wrappedBuffer(strBuilder.toString().getBytes(StandardCharsets.UTF_8)));
+
+        httpResponse.headers().set(HttpHeaders.Names.CONTENT_TYPE,
+                "text/html; charset=UTF-8");
+
+        // TODO: httpResponse converter required
+
+        return httpResponse;
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/util/Cbor.java b/cloud/stack/src/main/java/org/iotivity/cloud/util/Cbor.java
new file mode 100644 (file)
index 0000000..565cfe9
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.io.IOException;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
+
+public class Cbor<T> {
+    private CBORFactory  f;
+    private ObjectMapper mapper;
+
+    public Cbor() {
+        f = new CBORFactory();
+        mapper = new ObjectMapper(f);
+    }
+
+    @SuppressWarnings("unchecked")
+    public T parsePayloadFromCbor(byte[] cborPayload,
+            Class<? extends Object> class1) {
+        T payload = null;
+        try {
+            payload = (T) mapper.readValue(cborPayload, class1);
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        return payload;
+    }
+
+    public byte[] encodingPayloadToCbor(Object payload) {
+        byte[] cborData = null;
+        try {
+            cborData = mapper.writeValueAsBytes(payload);
+        } catch (JsonProcessingException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        return cborData;
+    }
+}
\ No newline at end of file
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/util/CoapLogHandler.java b/cloud/stack/src/main/java/org/iotivity/cloud/util/CoapLogHandler.java
new file mode 100644 (file)
index 0000000..b1d2601
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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 org.iotivity.cloud.base.protocols.coap.CoapMessage;
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandler.Sharable;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+
+/**
+ *
+ * This class provides a set of APIs to print out logs for CoAP request and
+ * response.
+ *
+ */
+@Sharable
+public class CoapLogHandler extends ChannelDuplexHandler {
+
+    @Override
+    public void write(ChannelHandlerContext ctx, Object msg,
+            ChannelPromise promise) {
+
+        if (msg instanceof CoapMessage) {
+
+            CoapMessage coapMessage = (CoapMessage) msg;
+
+            StringBuilder strBuilder = new StringBuilder();
+            strBuilder.append(getStringCtx(ctx));
+            strBuilder.append(
+                    "\n/******************************************************************************/\n");
+            strBuilder.append(getStringCoapMessage(coapMessage));
+            strBuilder.append(
+                    "\n/******************************************************************************/\n");
+            Logger.d(strBuilder.toString());
+
+        } else if (msg instanceof String) {
+
+            String message = (String) msg;
+
+            StringBuilder strBuilder = new StringBuilder();
+            strBuilder.append(getStringCtx(ctx));
+            strBuilder.append(
+                    "\n/******************************************************************************/\n");
+            strBuilder.append(message);
+            strBuilder.append(
+                    "\n/******************************************************************************/\n");
+            Logger.d(strBuilder.toString());
+
+            ByteBuf outByteBuf = ctx.alloc().buffer();
+            outByteBuf.writeBytes(message.getBytes());
+        }
+
+        ctx.write(msg);
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg)
+            throws Exception {
+
+        if (msg instanceof CoapMessage) {
+
+            CoapMessage coapMessage = (CoapMessage) msg;
+
+            StringBuilder strBuilder = new StringBuilder();
+            strBuilder.append(getStringCtx(ctx));
+            strBuilder.append(
+                    "\n/******************************************************************************/\n");
+            strBuilder.append(getStringCoapMessage(coapMessage));
+            strBuilder.append(
+                    "\n/******************************************************************************/\n");
+            Logger.d(strBuilder.toString());
+
+        } else if (msg instanceof ByteBuf) {
+
+            ByteBuf inByteBuf = (ByteBuf) msg;
+
+            String message = null;
+            StringBuffer strBuffer = new StringBuffer();
+            while (inByteBuf.isReadable()) {
+                strBuffer.append((char) inByteBuf.readByte());
+            }
+            message = strBuffer.toString();
+
+            StringBuilder strBuilder = new StringBuilder();
+            strBuilder.append(getStringCtx(ctx));
+            strBuilder.append(
+                    "\n/******************************************************************************/\n");
+            strBuilder.append(message);
+            strBuilder.append(
+                    "\n/******************************************************************************/\n");
+            Logger.d(strBuilder.toString());
+        }
+
+        ctx.fireChannelRead(msg);
+    }
+
+    private String getStringCtx(ChannelHandlerContext ctx) {
+
+        StringBuilder strBuilder = new StringBuilder();
+
+        strBuilder.append("\n");
+        strBuilder.append("Local Address: ");
+        strBuilder.append(ctx.channel().localAddress().toString());
+
+        strBuilder.append("\n");
+        strBuilder.append("Remote Address: ");
+        strBuilder.append(ctx.channel().remoteAddress().toString());
+
+        return strBuilder.toString();
+    }
+
+    private String getStringCoapMessage(CoapMessage coapMessage) {
+
+        StringBuilder strBuilder = new StringBuilder();
+
+        strBuilder.append("Code: ");
+        strBuilder.append(coapMessage.getCode());
+        strBuilder.append("\n");
+
+        strBuilder.append("Token Length: ");
+        strBuilder.append(coapMessage.getTokenLength());
+        strBuilder.append("\n");
+
+        strBuilder.append("Token Data: ");
+        strBuilder.append(coapMessage.getTokenString());
+        strBuilder.append("\n");
+
+        if (coapMessage instanceof CoapRequest) {
+
+            CoapRequest coapRequest = (CoapRequest) coapMessage;
+
+            strBuilder.append("Option URI_PATH: ");
+            strBuilder.append(coapRequest.getUriPath());
+            strBuilder.append("\n");
+
+            strBuilder.append("Option URI_QUERY: ");
+            strBuilder.append(coapRequest.getUriQuery());
+            strBuilder.append("\n");
+        }
+
+        strBuilder.append("Option CONTENT_FORMAT: ");
+        strBuilder.append(coapMessage.getContentFormatString());
+        strBuilder.append("\n");
+
+        strBuilder.append("Payload Length: ");
+        strBuilder.append(coapMessage.getPayloadSize());
+
+        strBuilder.append("\n");
+        strBuilder.append("Payload Data: ");
+        strBuilder.append(coapMessage.getPayloadString());
+
+        return strBuilder.toString();
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/util/JSONUtil.java b/cloud/stack/src/main/java/org/iotivity/cloud/util/JSONUtil.java
new file mode 100644 (file)
index 0000000..72e4719
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * 
+ * This class provides utility for parsing JSON object and converting data to
+ * JSON string.
+ * 
+ */
+public class JSONUtil {
+
+    private static ObjectMapper mapper = new ObjectMapper();
+
+    public static String parseJSON(String jsonString, String key) {
+
+        if (jsonString == null || jsonString.equals(""))
+            return null;
+
+        String value = null;
+
+        try {
+            @SuppressWarnings("unchecked")
+            Map<String, String> jsonMap = mapper.readValue(jsonString,
+                    Map.class);
+            value = jsonMap.get(key);
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+
+        return value;
+    }
+
+    public static Map<String, String> parseJSON(String jsonString)
+            throws JsonParseException, JsonMappingException, IOException {
+
+        Map<String, String> map = null;
+
+        try {
+            @SuppressWarnings("unchecked")
+            Map<String, String> jsonMap = mapper.readValue(jsonString,
+                    Map.class);
+            map = jsonMap;
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+
+        return map;
+    }
+
+    public static String writeJSON(HashMap<Object, Object> data) {
+        if (data == null)
+            return null;
+
+        String json = null;
+        try {
+            json = mapper.writeValueAsString(data);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+
+        if (json == null)
+            json = "{}";
+
+        return json;
+    }
+}
diff --git a/cloud/stack/src/main/java/org/iotivity/cloud/util/Logger.java b/cloud/stack/src/main/java/org/iotivity/cloud/util/Logger.java
new file mode 100644 (file)
index 0000000..fce3f51
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.text.SimpleDateFormat;
+import java.util.Calendar;
+
+public class Logger {
+
+    public static final int VERBOSE = 0;
+    public static final int DEBUG   = 1;
+    public static final int INFO    = 2;
+    public static final int WARNING = 3;
+    public static final int ERROR   = 4;
+
+    private static int logLevel = DEBUG;
+
+    public static void setLogLevel(int level) {
+        logLevel = level;
+    }
+
+    public static void v(String log) {
+        printLog(VERBOSE, log);
+    }
+
+    public static void d(String log) {
+        printLog(DEBUG, log);
+    }
+
+    public static void i(String log) {
+        printLog(INFO, log);
+    }
+
+    public static void w(String log) {
+        printLog(WARNING, log);
+    }
+
+    public static void e(String log) {
+        printLog(ERROR, log);
+    }
+
+    public static void w(String log, Exception ex) {
+        printLog(WARNING, log);
+        ex.printStackTrace();
+    }
+
+    public static void w(String log, Throwable th) {
+        printLog(WARNING, log);
+        th.printStackTrace();
+    }
+
+    public static void e(String log, Exception ex) {
+        printLog(ERROR, log);
+        ex.printStackTrace();
+    }
+
+    public static void e(String log, Throwable th) {
+        printLog(ERROR, log);
+        th.printStackTrace();
+    }
+
+    private static void printLog(int level, String log) {
+
+        if (logLevel > level)
+            return;
+
+        String format = "";
+        format += getTime();
+        format += " [" + getLogLevelString(level) + "]";
+
+        if (level >= ERROR) {
+            format += " [" + getDetailInfo() + "]";
+        }
+
+        format += " " + log;
+
+        System.out.println(format);
+    }
+
+    private static String getDetailInfo() {
+
+        String res = "";
+
+        StackTraceElement ste = Thread.currentThread().getStackTrace()[4];
+        String className = ste.getClassName()
+                .substring(ste.getClassName().lastIndexOf(".") + 1);
+
+        res += ste.getFileName() + ", " + className + "." + ste.getMethodName()
+                + "(), line:" + ste.getLineNumber();
+
+        return res;
+    }
+
+    private static String getTime() {
+        Calendar calendar = Calendar.getInstance();
+        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss:SSS");
+
+        return dateFormat.format(calendar.getTime());
+    }
+
+    private static String getLogLevelString(int level) {
+
+        String res = "";
+
+        if (level == VERBOSE) {
+            res = "V";
+        } else if (level == DEBUG) {
+            res = "D";
+        } else if (level == INFO) {
+            res = "I";
+        } else if (level == WARNING) {
+            res = "W";
+        } else if (level == ERROR) {
+            res = "E";
+        }
+
+        return res;
+    }
+}
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
new file mode 100644 (file)
index 0000000..e6804fb
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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/base/CoapClientTest.java b/cloud/stack/src/test/java/org/iotivity/cloud/base/CoapClientTest.java
new file mode 100644 (file)
index 0000000..7eadf51
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base;
+
+import java.net.InetSocketAddress;
+
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+import org.iotivity.cloud.base.protocols.coap.enums.CoapMethod;
+import org.junit.Test;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+
+public class CoapClientTest {
+
+    private static class CoapHandler
+            extends SimpleChannelInboundHandler<CoapRequest> {
+        @Override
+        protected void channelRead0(ChannelHandlerContext ctx, CoapRequest msg)
+                throws Exception {
+            // TODO Auto-generated method stub
+        }
+    }
+
+    @Test
+    public void testAddHandler() throws Exception {
+        CoapServer coapServer = new CoapServer();
+        coapServer.startServer(new InetSocketAddress(5683));
+        CoapClient coapClient = new CoapClient();
+        coapClient.startClient(new InetSocketAddress("127.0.0.1", 5683));
+        coapClient.addHandler(new CoapHandler());
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testAddHandlerSendRequest() throws Exception {
+        CoapServer coapServer = new CoapServer();
+        coapServer.startServer(new InetSocketAddress(5683));
+
+        CoapClient coapClient = new CoapClient();
+        coapClient.startClient(new InetSocketAddress("127.0.0.1", 5683));
+        coapClient.addHandler(new CoapHandler());
+
+        CoapRequest request = new CoapRequest(CoapMethod.GET);
+        coapClient.sendRequest(request);
+
+        CoapRequest request2 = new CoapRequest(CoapMethod.GET);
+        request2.setToken("1234".getBytes());
+        coapClient.sendRequest(request2);
+
+        CoapRequest request3 = new CoapRequest(CoapMethod.GET);
+        request3.setPayload("sample1".getBytes());
+        coapClient.sendRequest(request3);
+
+        CoapRequest request4 = new CoapRequest(CoapMethod.GET);
+        request4.setToken("5576".getBytes());
+        request4.setPayload("sample2".getBytes());
+        coapClient.sendRequest(request4);
+
+        CoapRequest request5 = new CoapRequest(CoapMethod.GET);
+        request5.setToken("565761".getBytes());
+        coapClient.sendRequest(request5);
+
+        CoapRequest request6 = new CoapRequest(CoapMethod.GET);
+        coapClient.sendRequest(request6);
+
+        CoapRequest request7 = new CoapRequest(CoapMethod.GET);
+        coapClient.sendRequest(request7);
+
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testStartStopClient() throws Exception {
+        CoapServer coapServer = new CoapServer();
+        coapServer.startServer(new InetSocketAddress(5683));
+        CoapClient coapClient = new CoapClient();
+        coapClient.startClient(new InetSocketAddress("127.0.0.1", 5683));
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+
+    @Test
+    public void testSendRequest() throws Exception {
+        CoapServer coapServer = new CoapServer();
+        coapServer.startServer(new InetSocketAddress(5683));
+        CoapClient coapClient = new CoapClient();
+        coapClient.startClient(new InetSocketAddress("127.0.0.1", 5683));
+        CoapRequest request = new CoapRequest(CoapMethod.GET);
+        coapClient.sendRequest(request);
+        coapClient.stopClient();
+        coapServer.stopServer();
+    }
+}
diff --git a/cloud/stack/src/test/java/org/iotivity/cloud/base/CoapServerTest.java b/cloud/stack/src/test/java/org/iotivity/cloud/base/CoapServerTest.java
new file mode 100644 (file)
index 0000000..5ae72f6
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * //******************************************************************
+ * //
+ * // 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.base;
+
+import java.net.InetSocketAddress;
+
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+import org.junit.Test;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+
+public class CoapServerTest {
+    private static class CoapHandler
+            extends SimpleChannelInboundHandler<CoapRequest> {
+        @Override
+        protected void channelRead0(ChannelHandlerContext ctx, CoapRequest msg)
+                throws Exception {
+            // TODO Auto-generated method stub
+        }
+    }
+
+    @Test
+    public void testAddHandler() throws Exception {
+        CoapServer server = new CoapServer();
+        server.startServer(new InetSocketAddress(5683));
+        server.addHandler(new CoapHandler());
+        server.stopServer();
+    }
+
+    @Test
+    public void testStartStopServer() throws Exception {
+        CoapServer server = new CoapServer();
+        server.startServer(new InetSocketAddress(5683));
+        server.stopServer();
+    }
+}