[IOT-1527] add GroupBrokerManager, GroupPolicyManager to check authorization
authoreunok.shin <eunok.shin@samsung.com>
Thu, 20 Oct 2016 10:01:48 +0000 (19:01 +0900)
committerJee Hyeok Kim <jihyeok13.kim@samsung.com>
Tue, 17 Jan 2017 02:29:49 +0000 (02:29 +0000)
Change-Id: Ie812c968c2b6daa5c7c544e7352b4f94a7d7994d
Signed-off-by: eunok.shin <eunok.shin@samsung.com>
Signed-off-by: yeonghun.nam <yeonghun.nam@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/13611
Reviewed-by: Jee Hyeok Kim <jihyeok13.kim@samsung.com>
Tested-by: Jee Hyeok Kim <jihyeok13.kim@samsung.com>
(cherry picked from commit a72600e7f7dc16a74109af58032c5eb7ff454a7d)
Reviewed-on: https://gerrit.iotivity.org/gerrit/14557
Reviewed-by: Uze Choi <uzchoi@samsung.com>
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-on: https://gerrit.iotivity.org/gerrit/16077

cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/MasterAuthorization.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/MemberAuthorization.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/OwnerAuthorization.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/UserAuthorization.java [new file with mode: 0644]
cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/GroupBrokerManager.java
cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/GroupPolicyManager.java
cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/UserOperation.java [new file with mode: 0644]
cloud/account/src/test/java/org/iotivity/cloud/accountserver/resources/acl/group/GroupBrokerTest.java [new file with mode: 0644]
cloud/stack/src/main/java/org/iotivity/cloud/base/OICConstants.java

diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/MasterAuthorization.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/MasterAuthorization.java
new file mode 100644 (file)
index 0000000..b5abb6b
--- /dev/null
@@ -0,0 +1,24 @@
+package org.iotivity.cloud.accountserver.resources.acl.group.Authorization;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This file contains the declaration of masters's authorization
+ *
+ */
+public class MasterAuthorization extends UserAuthorization {
+    private List<String> masterAddList     = Arrays.asList(GROUP, DEVICES,
+            RESOURCES, MASTERS, MEMBERS);
+
+    private List<String> masterReplaceList = Arrays.asList(GNAME);
+
+    private List<String> masterDeleteList  = Arrays.asList(DEVICES, RESOURCES,
+            MASTERS, MEMBERS);
+
+    public MasterAuthorization() {
+        super.addList.addAll(masterAddList);
+        super.replaceList.addAll(masterReplaceList);
+        super.deleteList.addAll(masterDeleteList);
+    }
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/MemberAuthorization.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/MemberAuthorization.java
new file mode 100644 (file)
index 0000000..684e460
--- /dev/null
@@ -0,0 +1,23 @@
+package org.iotivity.cloud.accountserver.resources.acl.group.Authorization;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This file contains the declaration of member's authorization
+ *
+ */
+public class MemberAuthorization extends UserAuthorization {
+    private List<String> memberAddList     = Arrays.asList(DEVICES, RESOURCES);
+
+    private List<String> memberReplaceList = Arrays.asList(GNAME);
+
+    private List<String> memberDeleteList  = Arrays.asList(DEVICES, RESOURCES,
+            MEMBERS);
+
+    public MemberAuthorization() {
+        super.addList.addAll(memberAddList);
+        super.replaceList.addAll(memberReplaceList);
+        super.deleteList.addAll(memberDeleteList);
+    }
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/OwnerAuthorization.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/OwnerAuthorization.java
new file mode 100644 (file)
index 0000000..69a75b7
--- /dev/null
@@ -0,0 +1,25 @@
+package org.iotivity.cloud.accountserver.resources.acl.group.Authorization;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This file contains the declaration of owner's authorization
+ *
+ */
+public class OwnerAuthorization extends UserAuthorization {
+
+    private List<String> ownerAddList     = Arrays.asList(GROUP, DEVICES,
+            RESOURCES, MASTERS, MEMBERS);
+
+    private List<String> ownerReplaceList = Arrays.asList(OWNER, GNAME);
+
+    private List<String> ownerDeleteList  = Arrays.asList(GROUP, DEVICES,
+            RESOURCES, MASTERS, MEMBERS);
+
+    public OwnerAuthorization() {
+        super.addList.addAll(ownerAddList);
+        super.replaceList.addAll(ownerReplaceList);
+        super.deleteList.addAll(ownerDeleteList);
+    }
+}
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/UserAuthorization.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/Authorization/UserAuthorization.java
new file mode 100644 (file)
index 0000000..d2eabe1
--- /dev/null
@@ -0,0 +1,51 @@
+package org.iotivity.cloud.accountserver.resources.acl.group.Authorization;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.iotivity.cloud.accountserver.Constants;
+import org.iotivity.cloud.accountserver.resources.acl.group.UserOperation;
+import org.iotivity.cloud.base.exception.ServerException.BadRequestException;
+
+/**
+ * This class provides a set of API to handle user's authorization
+ *
+ */
+public class UserAuthorization {
+
+    static final String GROUP       = Constants.KEYFIELD_GROUP;
+    static final String DEVICES     = Constants.KEYFIELD_GROUP_DEVICES;
+    static final String RESOURCES   = Constants.KEYFIELD_GROUP_RESOURCES;
+    static final String MASTERS     = Constants.KEYFIELD_GROUP_MASTERS;
+    static final String MEMBERS     = Constants.KEYFIELD_GROUP_MEMBERS;
+    static final String OWNER       = Constants.KEYFIELD_GROUP_OWNER;
+    static final String GNAME       = Constants.KEYFIELD_GROUP_NAME;
+
+    public List<String> addList     = new ArrayList<String>();
+    public List<String> replaceList = new ArrayList<String>();
+    public List<String> deleteList  = new ArrayList<String>();
+    public List<String> properties  = new ArrayList<String>();
+
+    public UserAuthorization() {
+        properties.addAll(Arrays.asList(GROUP, GNAME, MASTERS, MEMBERS, OWNER,
+                DEVICES, RESOURCES));
+    }
+
+    public List<String> getProperties() {
+        return properties;
+    }
+
+    public List<String> getUserAuthz(UserOperation operation) {
+        switch (operation) {
+            case ADD:
+                return addList;
+            case REPLACE:
+                return replaceList;
+            case DELETE:
+                return deleteList;
+            default:
+                throw new BadRequestException("operation type is not support");
+        }
+    }
+}
index 9772842..d68490c 100644 (file)
 package org.iotivity.cloud.accountserver.resources.acl.group;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.ListIterator;
+import java.util.UUID;
 
+import org.iotivity.cloud.accountserver.Constants;
+import org.iotivity.cloud.accountserver.db.AccountDBManager;
+import org.iotivity.cloud.accountserver.db.GroupTable;
+import org.iotivity.cloud.accountserver.util.TypeCastingManager;
 import org.iotivity.cloud.base.device.Device;
+import org.iotivity.cloud.base.exception.ServerException.BadRequestException;
 import org.iotivity.cloud.base.protocols.IRequest;
+import org.iotivity.cloud.base.protocols.MessageBuilder;
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+import org.iotivity.cloud.base.protocols.enums.ContentFormat;
+import org.iotivity.cloud.base.protocols.enums.ResponseStatus;
+import org.iotivity.cloud.util.Cbor;
+import org.iotivity.cloud.util.Log;
 
+/**
+ * This class provides a set of APIs manage a group broker
+ */
 public class GroupBrokerManager {
-    public void verifyAuthorization(String mid, String gid,
-            HashMap<String, Object> properties) {
+
+    private static GroupBrokerManager                   mGroupBrokerMgr    = new GroupBrokerManager();
+    private TypeCastingManager<GroupTable>              mTypeGroup         = new TypeCastingManager<>();
+    private HashMap<String, Object>                     mGroupResourceInfo = new HashMap<>();
+
+    private HashMap<String, ArrayList<GroupSubscriber>> mGroupSubscriber   = new HashMap<>();
+
+    private Cbor<HashMap<String, Object>>               mCbor              = new Cbor<>();
+
+    private GroupPolicyManager                          mGroupPolicyMgr    = new GroupPolicyManager();
+
+    private GroupBrokerManager() {
+        mGroupResourceInfo.put(Constants.RS_RESOURCE_TYPE,
+                Constants.ACL_RESOURCE_TYPE);
+        mGroupResourceInfo.put(Constants.RS_INTERFACE,
+                Constants.DEFAULT_INTERFACE);
+    }
+
+    /**
+     * Function to get GroupBrokerManager as a singleton
+     * 
+     * @return GroupBrokerManager as a singleton
+     */
+    public static GroupBrokerManager getInstance() {
+        return mGroupBrokerMgr;
+    }
+
+    private class GroupSubscriber {
+        GroupSubscriber(Device subscriber, IRequest request) {
+            mSubscriber = subscriber;
+            mRequest = request;
+        }
+
+        public Device   mSubscriber;
+        public IRequest mRequest;
+    }
+
+    /**
+     * API to verify user's Authorization
+     * 
+     * @param uid
+     *            unique user id
+     * @param gid
+     *            group id
+     * @param properties
+     *            payload properties
+     * @param op
+     *            operation
+     */
+    public void verifyAuthorization(String uid, String gid,
+            ArrayList<String> properties, UserOperation op) {
+
+        if (gid == null) {
+            return;
+        }
+
+        mGroupPolicyMgr.verifyOperationAuthorization(gid, uid, op, properties);
+    }
+
+    /**
+     * API to get Group information
+     * 
+     * @param uid
+     *            unique user id
+     * @return response message
+     */
+    public HashMap<String, Object> getGroupList(String uid) {
+
+        return makeGetResponse(uid);
 
     }
 
-    public void getGroupList(String mid) {
+    private HashMap<String, Object> makeGetResponse(String uid) {
 
+        ArrayList<HashMap<String, Object>> records = readGroupInfo(
+                Constants.KEYFIELD_GROUP_MEMBERS, uid);
+
+        HashMap<String, Object> response = new HashMap<>();
+        // put group info
+        response.putAll(mGroupResourceInfo);
+        if (!records.isEmpty()) {
+            response.put(Constants.RESP_GROUPS, records);
+        }
+
+        Log.d("Group get response : " + response.toString());
+        return response;
     }
 
-    public void createGroup(String mid, String gname, String upperGroup) {
+    private ArrayList<HashMap<String, Object>> readGroupInfo(String key,
+            String value) {
+        HashMap<String, Object> condition = new HashMap<>();
+        condition.put(key, value);
+        ArrayList<HashMap<String, Object>> records = AccountDBManager
+                .getInstance().selectRecord(Constants.GROUP_TABLE, condition);
+        return records;
+    }
+
+    /**
+     * API to create a group
+     * 
+     * @param uid
+     *            unique user id
+     * @param gid
+     *            group id
+     * @param gname
+     *            group name
+     * @param parent
+     *            parent group id
+     * @return response message
+     */
+    public HashMap<String, Object> createGroup(String uid, String gid,
+            String gname, String parent) {
+
+        if (gname == null) {
+            gname = "DEFAULT_GNAME";
+        }
 
+        if (gid == null) {
+            gid = UUID.randomUUID().toString();
+        }
+
+        if (parent != null) {
+            // parent update
+            HashMap<String, Object> condition = new HashMap<>();
+            condition.put(Constants.KEYFIELD_GID, parent);
+            HashMap<String, Object> record = AccountDBManager.getInstance()
+                    .selectOneRecord(Constants.GROUP_TABLE, condition);
+
+            if (record.isEmpty()) {
+                throw new BadRequestException("parent group is null");
+            }
+            ArrayList<String> subgroups = (ArrayList<String>) record
+                    .get(Constants.KEYFIELD_GROUP_SUBGROUPS);
+            if (subgroups == null) {
+                subgroups = new ArrayList<String>();
+            }
+            subgroups.add(gid);
+            record.put(Constants.KEYFIELD_GROUP_SUBGROUPS, subgroups);
+            AccountDBManager.getInstance()
+                    .insertAndReplaceRecord(Constants.GROUP_TABLE, record);
+        }
+
+        storeGroupInfo(uid, gid, gname, parent);
+        return makePostResponse(gid, gname);
     }
 
-    public void addObserver(String mid, Device srcDevice, IRequest request) {
+    private HashMap<String, Object> makePostResponse(String gid, String gname) {
+
+        HashMap<String, Object> response = new HashMap<>();
+        response.put(Constants.KEYFIELD_GID, gid);
+        response.put(Constants.KEYFIELD_GROUP_NAME, gname);
 
+        Log.d("Group post response : " + response.toString());
+
+        return response;
+    }
+
+    private void storeGroupInfo(String uid, String gid, String gname,
+            String parent) {
+        GroupTable groupTable = new GroupTable();
+        groupTable.setGid(gid);
+        groupTable.setGname(gname);
+        groupTable.setOwner(uid);
+        ArrayList<String> members = new ArrayList<>();
+        members.add(uid);
+        groupTable.setMembers(members);
+        if (parent != null) {
+            groupTable.setParent(parent);
+        }
+
+        HashMap<String, Object> groupMap = mTypeGroup
+                .convertObjectToMap(groupTable);
+        groupMap.putAll(mGroupResourceInfo);
+        AccountDBManager.getInstance().insertRecord(Constants.GROUP_TABLE,
+                groupMap);
+
+    }
+
+    /**
+     * API to add a observer
+     * 
+     * @param uid
+     *            unique user id
+     * @param srcDevice
+     *            channel information
+     * @param request
+     *            request message
+     */
+    public void addObserver(String uid, Device srcDevice, IRequest request) {
+        ArrayList<GroupSubscriber> subscribers = mGroupSubscriber.get(uid);
+        if (subscribers == null) {
+            mGroupSubscriber.put(uid, new ArrayList<GroupSubscriber>(
+                    Arrays.asList(new GroupSubscriber(srcDevice, request))));
+            return;
+        }
+        // TODO control consecutive GET observe requests from single device
+        // removeObserverFromSubscriberList(uid, srcDevice, request);
+        GroupSubscriber subscriber = new GroupSubscriber(srcDevice, request);
+        subscribers.add(subscriber);
+        mGroupSubscriber.put(uid, subscribers);
     }
 
-    public void removeObserver(String mid, IRequest request) {
+    /**
+     * API to remove a observer
+     * 
+     * @param uid
+     *            unique user id
+     * @param srcDevice
+     *            channel information
+     * @param request
+     *            request message
+     */
+    public void removeObserver(String uid, Device srcDevice, IRequest request) {
+        removeObserverFromSubscriberList(uid, srcDevice, request);
+    }
 
+    private void removeObserverFromSubscriberList(String uid, Device srcDevice,
+            IRequest request) {
+        ArrayList<GroupSubscriber> subscribers = mGroupSubscriber.get(uid);
+        if (subscribers != null) {
+            ListIterator<GroupSubscriber> iterator = subscribers.listIterator();
+            while (iterator.hasNext()) {
+                GroupSubscriber subscriber = iterator.next();
+                CoapRequest coapRequest = (CoapRequest) subscriber.mRequest;
+                if (srcDevice.equals(subscriber.mSubscriber)
+                        && coapRequest.getTokenString().equals(
+                                ((CoapRequest) request).getTokenString())) {
+                    iterator.remove();
+                    Log.d("subscriber removed, "
+                            + ((CoapRequest) request).getTokenString());
+                }
+            }
+            mGroupSubscriber.put(uid, subscribers);
+        }
     }
 
-    public void notiryToObservers(String mid) {
+    /**
+     * API to notify to observers
+     * 
+     * @param uidList
+     *            unique user id list
+     */
+    public void notifyToObservers(ArrayList<String> uidList) {
 
+        if (uidList == null) {
+            return;
+        }
+        for (String uid : uidList) {
+            ArrayList<GroupSubscriber> subscribers = mGroupSubscriber.get(uid);
+            if (subscribers != null) {
+                ArrayList<String> subscriberTokenList = new ArrayList<>();
+                for (GroupSubscriber subscriber : subscribers) {
+                    subscriberTokenList.add(((CoapRequest) subscriber.mRequest)
+                            .getTokenString());
+                    subscriber.mSubscriber.sendResponse(
+                            MessageBuilder.createResponse(subscriber.mRequest,
+                                    ResponseStatus.CONTENT,
+                                    ContentFormat.APPLICATION_CBOR,
+                                    mCbor.encodingPayloadToCbor(
+                                            makeGetResponse(uid))));
+                }
+                Log.d("subscriber : " + uid
+                        + " , subscriber internal Token list : "
+                        + subscriberTokenList);
+            }
+        }
     }
 }
index 567d54d..b1a9542 100644 (file)
 package org.iotivity.cloud.accountserver.resources.acl.group;
 
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
 
+import org.iotivity.cloud.accountserver.Constants;
+import org.iotivity.cloud.accountserver.db.AccountDBManager;
+import org.iotivity.cloud.accountserver.db.GroupTable;
+import org.iotivity.cloud.accountserver.resources.acl.group.Authorization.MasterAuthorization;
+import org.iotivity.cloud.accountserver.resources.acl.group.Authorization.MemberAuthorization;
+import org.iotivity.cloud.accountserver.resources.acl.group.Authorization.OwnerAuthorization;
+import org.iotivity.cloud.accountserver.resources.acl.group.Authorization.UserAuthorization;
+import org.iotivity.cloud.accountserver.util.TypeCastingManager;
+import org.iotivity.cloud.base.exception.ServerException.BadRequestException;
+
+/**
+ * This class provides a set of APIs to verify Authorization
+ *
+ */
 public class GroupPolicyManager {
-    public ArrayList<String> getUserAuthorization(String mid) {
-        ArrayList<String> userAuthz = null;
+
+    private TypeCastingManager<GroupTable> mTypeGroup = new TypeCastingManager<>();
+
+    /**
+     * API to verify user's authorization
+     * 
+     * @param gid
+     *            group id
+     * @param mid
+     *            user id
+     * @param operation
+     *            post message operation (add / delete)
+     * @param properties
+     *            payload properies
+     */
+    public void verifyOperationAuthorization(String gid, String mid,
+            UserOperation operation, ArrayList<String> properties) {
+
+        UserAuthorization userAuthz = getUserGrade(gid, mid);
+        checkPayloadProperties(userAuthz, properties);
+        checkOperationAuthz(userAuthz, operation, properties);
+    }
+
+    private UserAuthorization getUserGrade(String gid, String mid) {
+        HashMap<String, Object> condition = new HashMap<>();
+        condition.put(Constants.KEYFIELD_GID, gid);
+        HashMap<String, Object> record = AccountDBManager.getInstance()
+                .selectOneRecord(Constants.GROUP_TABLE, condition);
+
+        if (record.isEmpty()) {
+            throw new BadRequestException("gid doesn't exist");
+
+        }
+        GroupTable groupInfo = new GroupTable();
+        mTypeGroup.convertMaptoObject(record, groupInfo);
+
+        UserAuthorization userAuthz = null;
+        if (groupInfo.getOwner() != null && groupInfo.getOwner().equals(mid)) {
+            userAuthz = new OwnerAuthorization();
+        }
+
+        else if (groupInfo.getMasters() != null
+                && groupInfo.getMasters().contains(mid)) {
+            userAuthz = new MasterAuthorization();
+        }
+
+        else if (groupInfo.getMembers() != null
+                && groupInfo.getMembers().contains(mid)) {
+            userAuthz = new MemberAuthorization();
+        }
+
+        else {
+            throw new BadRequestException("mid is not members");
+        }
 
         return userAuthz;
+
+    }
+
+    private void checkPayloadProperties(UserAuthorization userAuthz,
+            List<String> properties) {
+        List<String> possibleProperties = userAuthz.getProperties();
+        if (!possibleProperties.containsAll(properties)) {
+            throw new BadRequestException("payload include invalid property");
+        }
+
     }
 
-    public boolean verifyOperationAuthorization(ArrayList<String> userAuthz,
-            int operation, ArrayList<String> properties) {
+    private void checkOperationAuthz(UserAuthorization userAuthz,
+            UserOperation operation, List<String> properties) {
+        List<String> opAuthz = userAuthz.getUserAuthz(operation);
 
-        return true;
+        for (String property : properties) {
+            if (!opAuthz.contains(property))
+                throw new BadRequestException(
+                        "user doesn't have authorization about '" + property
+                                + "' property");
+        }
     }
 }
diff --git a/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/UserOperation.java b/cloud/account/src/main/java/org/iotivity/cloud/accountserver/resources/acl/group/UserOperation.java
new file mode 100644 (file)
index 0000000..9d5c9fa
--- /dev/null
@@ -0,0 +1,5 @@
+package org.iotivity.cloud.accountserver.resources.acl.group;
+
+public enum UserOperation {
+    ADD, REPLACE, DELETE
+}
diff --git a/cloud/account/src/test/java/org/iotivity/cloud/accountserver/resources/acl/group/GroupBrokerTest.java b/cloud/account/src/test/java/org/iotivity/cloud/accountserver/resources/acl/group/GroupBrokerTest.java
new file mode 100644 (file)
index 0000000..6dfa5a3
--- /dev/null
@@ -0,0 +1,215 @@
+package org.iotivity.cloud.accountserver.resources.acl.group;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+
+import org.iotivity.cloud.accountserver.Constants;
+import org.iotivity.cloud.accountserver.db.MongoDB;
+import org.iotivity.cloud.base.device.CoapDevice;
+import org.iotivity.cloud.base.exception.ServerException;
+import org.iotivity.cloud.base.protocols.IRequest;
+import org.iotivity.cloud.base.protocols.IResponse;
+import org.iotivity.cloud.base.protocols.MessageBuilder;
+import org.iotivity.cloud.base.protocols.coap.CoapRequest;
+import org.iotivity.cloud.base.protocols.coap.CoapResponse;
+import org.iotivity.cloud.base.protocols.enums.ContentFormat;
+import org.iotivity.cloud.base.protocols.enums.Observe;
+import org.iotivity.cloud.base.protocols.enums.RequestMethod;
+import org.iotivity.cloud.base.protocols.enums.ResponseStatus;
+import org.iotivity.cloud.util.Cbor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class GroupBrokerTest {
+
+    private String                        GROUP_URI         = Constants.GROUP_FULL_URI;
+    private String                        UID_QUERY         = "uid=";
+    private String                        mGid1             = "g1";
+    private String                        mGid2             = "g2";
+    private String                        mGname1           = "myHome";
+    private String                        mGname2           = "myroom";
+    private String                        mDi1              = "d1";
+    private String                        mDi2              = "d2";
+    private String                        mDi3              = "d3";
+    private String                        mUid1             = "u1";
+
+    CountDownLatch                        mLatch            = new CountDownLatch(
+            1);
+    private CoapDevice                    mMockDevice       = Mockito
+            .mock(CoapDevice.class);
+    private Cbor<HashMap<String, Object>> mCbor             = new Cbor<>();
+    private IResponse                     mResponse         = null;
+    private IResponse                     mResponseObserver = null;
+    private GroupResource                 mGroupResource    = new GroupResource();
+    private HashMap<String, Object>       mPayload          = new HashMap<>();
+    private GroupResource                 mGResource        = new GroupResource();
+
+    @Before
+    public void setUp() throws Exception {
+        mResponse = null;
+        mMockDevice = mock(CoapDevice.class);
+        mLatch = new CountDownLatch(1);
+        mGResource = new GroupResource();
+        // callback mock
+        resetDB();
+        Mockito.doAnswer(new Answer<Object>() {
+            @Override
+            public CoapResponse answer(InvocationOnMock invocation)
+                    throws Throwable {
+                CoapResponse resp = (CoapResponse) invocation.getArguments()[0];
+                mLatch.countDown();
+                mResponse = resp;
+                return resp;
+            }
+        }).when(mMockDevice).sendResponse(Mockito.anyObject());
+    }
+
+    @After
+    public void resetAccountDatabase() throws Exception {
+        MongoDB mongoDB = new MongoDB(Constants.DB_NAME);
+        mongoDB.createTable(Constants.USER_TABLE);
+        mongoDB.createTable(Constants.TOKEN_TABLE);
+        mongoDB.createTable(Constants.GROUP_TABLE);
+        mongoDB.createTable(Constants.ACL_TABLE);
+        // mongoDB.createTable(Constants.ACE_TABLE);
+    }
+
+    @Test
+    public void testCreateGroup() throws Exception {
+        getTestMethodName();
+        sendCreateGroupRequest(mMockDevice, mUid1, mGname1, null);
+        assertTrue(responseCodeCheck(mResponse, ResponseStatus.CHANGED));
+        assertTrue(checkProperty(mResponse, Constants.KEYFIELD_GID));
+        assertTrue(checkProperty(mResponse, Constants.KEYFIELD_GROUP_NAME));
+        assertTrue(mLatch.await(2L, SECONDS));
+    }
+
+    @Test
+    public void testCreateSubGroup() throws Exception {
+        getTestMethodName();
+        sendCreateGroupRequest(mMockDevice, mUid1, mGname1, null);
+        String gid = getProperty(mResponse, Constants.KEYFIELD_GID).toString();
+        sendCreateGroupRequest(mMockDevice, mUid1, null, gid);
+        assertTrue(responseCodeCheck(mResponse, ResponseStatus.CHANGED));
+        assertTrue(checkProperty(mResponse, Constants.KEYFIELD_GID));
+        assertTrue(checkProperty(mResponse, Constants.KEYFIELD_GROUP_NAME));
+        assertTrue(mLatch.await(2L, SECONDS));
+    }
+
+    @Test(expected = ServerException.BadRequestException.class)
+    public void testCreateSubGroupNotExistParentGroup() throws Exception {
+        getTestMethodName();
+        GroupBrokerManager.getInstance().createGroup(mUid1, mGid1, null, null);
+        sendCreateGroupRequest(mMockDevice, mUid1, null, mGid2);
+    }
+
+    @Test
+    public void testGetGroupList() throws Exception {
+        getTestMethodName();
+        GroupBrokerManager.getInstance().createGroup(mUid1, mGid1, null, null);
+        sendGetGroupResquest(mMockDevice, mUid1);
+        assertTrue(responseCodeCheck(mResponse, ResponseStatus.CONTENT));
+    }
+
+    @Test
+    public void testGetSubscribe() throws Exception {
+        getTestMethodName();
+        sendGetGroupResquest(mMockDevice, mUid1, Observe.SUBSCRIBE);
+        assertTrue(responseCodeCheck(mResponse, ResponseStatus.CONTENT));
+        ArrayList<String> uidList = new ArrayList<>();
+        uidList.add(mUid1);
+        mResponse = null;
+        GroupBrokerManager.getInstance().notifyToObservers(uidList);
+        assertTrue(responseCodeCheck(mResponse, ResponseStatus.CONTENT));
+    }
+
+    @Test
+    public void testUnsubscribe() throws Exception {
+        getTestMethodName();
+        sendGetGroupResquest(mMockDevice, mUid1, Observe.UNSUBSCRIBE);
+        assertTrue(responseCodeCheck(mResponse, ResponseStatus.CONTENT));
+        mResponse = null;
+        ArrayList<String> uidList = new ArrayList<>();
+        uidList.add(mUid1);
+        GroupBrokerManager.getInstance().notifyToObservers(uidList);
+        assertNull(mResponse);
+    }
+
+    private void sendCreateGroupRequest(CoapDevice device, String uid,
+            String gname, String parent) {
+        IRequest request = null;
+        HashMap<String, Object> payloadData = new HashMap<String, Object>();
+        payloadData.put(Constants.REQ_UUID_ID, uid);
+        payloadData.put(Constants.KEYFIELD_GROUP_NAME, gname);
+        payloadData.put(Constants.KEYFIELD_GROUP_PARENT, parent);
+        request = MessageBuilder.createRequest(RequestMethod.POST, GROUP_URI,
+                null, ContentFormat.APPLICATION_CBOR,
+                mCbor.encodingPayloadToCbor(payloadData));
+        mGroupResource.onDefaultRequestReceived(device, request);
+    }
+
+    private void sendGetGroupResquest(CoapDevice device, String uid) {
+        IRequest request = null;
+        request = MessageBuilder.createRequest(RequestMethod.GET, GROUP_URI,
+                UID_QUERY + uid);
+        mGroupResource.onDefaultRequestReceived(device, request);
+    }
+
+    private void sendGetGroupResquest(CoapDevice device, String uid,
+            Observe obs) {
+        IRequest request = null;
+        request = MessageBuilder.createRequest(RequestMethod.GET, GROUP_URI,
+                UID_QUERY + uid);
+        ((CoapRequest) request).setObserve(obs);
+        mGroupResource.onDefaultRequestReceived(device, request);
+    }
+
+    private void resetDB() throws Exception {
+        MongoDB mongoDB = new MongoDB(Constants.DB_NAME);
+        mongoDB.deleteTable(Constants.GROUP_TABLE);
+        mongoDB.createTable(Constants.GROUP_TABLE);
+        mongoDB.deleteTable(Constants.USER_TABLE);
+        mongoDB.createTable(Constants.USER_TABLE);
+        mongoDB.deleteTable(Constants.TOKEN_TABLE);
+        mongoDB.createTable(Constants.TOKEN_TABLE);
+    }
+
+    private void getTestMethodName() {
+        StackTraceElement[] stacks = new Throwable().getStackTrace();
+        StackTraceElement currentStack = stacks[1];
+        System.out.println("\t---Test Name : " + currentStack.getMethodName());
+    }
+
+    private boolean responseCodeCheck(IResponse response,
+            ResponseStatus responseStatus) {
+        if (responseStatus == response.getStatus())
+            return true;
+        else
+            return false;
+    }
+
+    private boolean checkProperty(IResponse response, String propertyName) {
+        HashMap<String, Object> payloadData = mCbor
+                .parsePayloadFromCbor(response.getPayload(), HashMap.class);
+        if (payloadData.containsKey(propertyName))
+            return true;
+        else
+            return false;
+    }
+
+    private Object getProperty(IResponse response, String propertyName) {
+        HashMap<String, Object> payloadData = mCbor
+                .parsePayloadFromCbor(response.getPayload(), HashMap.class);
+        return payloadData.get(propertyName);
+    }
+}
index 01d2de2..6e54131 100755 (executable)
@@ -31,6 +31,8 @@ public class OICConstants {
 
     public static final String RS_INTERFACE                  = "if";
 
+    public static final String RS_RESOURCE_TYPE              = "rt";
+
     /* resource url for account */
     public static final String ACCOUNT_URI                   = "account";