Fix issues of RCSResourceObject
authorcoderhyme <jhyo.kim@samsung.com>
Thu, 22 Oct 2015 04:24:25 +0000 (21:24 -0700)
committerHabib Virji <habib.virji@samsung.com>
Thu, 22 Oct 2015 09:08:45 +0000 (09:08 +0000)
Fix data race for handlers with shared_ptr which has guaranteed atomic operations for setting and loading.
LockGuard's destructor is now noexcept(false) and it will emit an exception if and only if the destruction is not caused by stack unwinding.
Some minor issues of the test are fixed.

Change-Id: I12ccb6adb4849642d266f7af5b1e28a2f6d35f83
Signed-off-by: coderhyme <jhyo.kim@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/3929
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Habib Virji <habib.virji@samsung.com>
service/resource-encapsulation/android/service/src/main/java/org/iotivity/service/server/RcsResourceObject.java
service/resource-encapsulation/android/service/src/main/jni/JniRcsLockedAttributes.cpp
service/resource-encapsulation/android/service/src/main/jni/JniRcsResourceObject.cpp
service/resource-encapsulation/include/RCSResourceObject.h
service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp
service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp

index f890404..915004e 100644 (file)
@@ -224,6 +224,8 @@ public final class RcsResourceObject extends RcsObject {
          *
          * @throws RcsIllegalStateException
          *             if not in locked state
+         * @throws RcsPlatformException
+         *             if auto notify failed
          */
         public void apply() throws RcsIllegalStateException {
             if (mCurrentAttributes == null) {
index 98273c9..ad05590 100644 (file)
@@ -25,6 +25,7 @@
 #include "JniRcsValue.h"
 #include "Log.h"
 #include "Verify.h"
+#include "JavaExceptions.h"
 
 #include "RCSResourceObject.h"
 
@@ -153,7 +154,15 @@ Java_org_iotivity_service_server_RcsLockedAttributes_nativeApply
     auto res = getResource(env, resourceObject);
     VERIFY_NO_EXC(env);
 
-    writeNativeAttributesFromMap(env, cacheObj, res->getAttributes());
+    try
+    {
+        RCSResourceObject::LockGuard lock(res);
+        writeNativeAttributesFromMap(env, cacheObj, res->getAttributes());
+    }
+    catch (const RCSPlatformException& e)
+    {
+        throwPlatformException(env, e);
+    }
 }
 
 JNIEXPORT void JNICALL
@@ -163,7 +172,8 @@ Java_org_iotivity_service_server_RcsLockedAttributes_nativeLock
     auto res = getResource(env, resourceObject);
     VERIFY_NO_EXC(env);
 
-    setSafeNativeHandle< RCSResourceObject::LockGuard >(env, obj, res);
+    setSafeNativeHandle< RCSResourceObject::LockGuard >(env, obj,
+            res, RCSResourceObject::AutoNotifyPolicy::NEVER);
 }
 
 JNIEXPORT void JNICALL
index 4354032..fe47ef8 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "RCSResourceObject.h"
 #include "RCSResponse.h"
+#include "RCSRequest.h"
 #include "RequestHandler.h"
 
 #define LOG_TAG "JNI-RCSResourceObject"
@@ -503,7 +504,7 @@ Java_org_iotivity_service_server_RcsResourceObject_nativeGetAttributes
     auto res = getResource(env, obj);
     VERIFY_NO_EXC_RET_DEF(env);
 
-    RCSResourceObject::LockGuard lock{ res };
+    RCSResourceObject::LockGuard lock{ res, RCSResourceObject::AutoNotifyPolicy::NEVER };
     return newAttributesObject(env, res->getAttributes());
 }
 
index 40044c6..d062b3a 100644 (file)
@@ -30,9 +30,8 @@
 #include <mutex>
 #include <thread>
 
-#include <RCSResourceAttributes.h>
-#include <RCSResponse.h>
-#include <RCSRequest.h>
+#include "RCSResourceAttributes.h"
+#include "RCSResponse.h"
 
 namespace OC
 {
@@ -44,6 +43,8 @@ namespace OIC
     namespace Service
     {
 
+        class RCSRequest;
+
         /**
          * @brief Thrown when lock has not been acquired.
          *
@@ -443,12 +444,12 @@ namespace OIC
         private:
             RCSResourceObject(uint8_t, RCSResourceAttributes&&);
 
-            OCEntityHandlerResult entityHandler(std::shared_ptr< OC::OCResourceRequest >);
+            OCEntityHandlerResult entityHandler(const std::shared_ptr< OC::OCResourceRequest >&);
 
-            OCEntityHandlerResult handleRequest(std::shared_ptr< OC::OCResourceRequest >);
-            OCEntityHandlerResult handleRequestGet(std::shared_ptr< OC::OCResourceRequest >);
-            OCEntityHandlerResult handleRequestSet(std::shared_ptr< OC::OCResourceRequest >);
-            OCEntityHandlerResult handleObserve(std::shared_ptr< OC::OCResourceRequest >);
+            OCEntityHandlerResult handleRequest(const std::shared_ptr< OC::OCResourceRequest >&);
+            OCEntityHandlerResult handleRequestGet(const std::shared_ptr< OC::OCResourceRequest >&);
+            OCEntityHandlerResult handleRequestSet(const std::shared_ptr< OC::OCResourceRequest >&);
+            OCEntityHandlerResult handleObserve(const std::shared_ptr< OC::OCResourceRequest >&);
 
             void expectOwnLock() const;
 
@@ -473,8 +474,8 @@ namespace OIC
 
             RCSResourceAttributes m_resourceAttributes;
 
-            GetRequestHandler m_getRequestHandler;
-            SetRequestHandler m_setRequestHandler;
+            std::shared_ptr< GetRequestHandler > m_getRequestHandler;
+            std::shared_ptr< SetRequestHandler > m_setRequestHandler;
 
             AutoNotifyPolicy m_autoNotifyPolicy;
             SetRequestHandlerPolicy m_setRequestHandlerPolicy;
@@ -495,8 +496,10 @@ namespace OIC
          * the RCSResourceObject it is given. When control leaves the scope in which the LockGuard
          * object was created, the LockGuard is destructed and the attributes is unlocked.
          *
-         * Additionally when this is destructed, it tries to notify depending on AutoNotifyPolicy
-         * of the RCSResourceObject.
+         * Additionally when it is destructed and only when destructed not by stack unwinding
+         * caused by an exception, it tries to notify depending on AutoNotifyPolicy.
+         *
+         * @note The destrcutor can throw an exception if auto notify failed.
          */
         class RCSResourceObject::LockGuard
         {
@@ -519,7 +522,13 @@ namespace OIC
             * @overload
             */
             LockGuard(const RCSResourceObject::Ptr, AutoNotifyPolicy);
-            ~LockGuard();
+
+            /**
+             * @throws RCSPlatformException If auto notify operation failed.
+             *
+             * @note The exception will never be thrown while stack unwinding.
+             */
+            ~LockGuard() noexcept(false);
 
             LockGuard(const LockGuard&) = delete;
             LockGuard(LockGuard&&) = delete;
index a68901a..6137df1 100644 (file)
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
-#include <RCSResourceObject.h>
+#include "RCSResourceObject.h"
 
 #include <string>
 #include <functional>
 #include <vector>
 
-#include <RequestHandler.h>
-#include <AssertUtils.h>
-#include <AtomicHelper.h>
-#include <ResourceAttributesConverter.h>
-#include <ResourceAttributesUtils.h>
+#include "RequestHandler.h"
+#include "AssertUtils.h"
+#include "AtomicHelper.h"
+#include "ResourceAttributesConverter.h"
+#include "ResourceAttributesUtils.h"
+#include "RCSRequest.h"
 
-#include <logger.h>
-#include <OCPlatform.h>
+#include "logger.h"
+#include "OCPlatform.h"
 
 #define LOG_TAG "RCSResourceObject"
 
@@ -56,7 +57,7 @@ namespace
 
     template <typename RESPONSE>
     OCEntityHandlerResult sendResponse(RCSResourceObject& resource,
-            std::shared_ptr< OC::OCResourceRequest > ocRequest, RESPONSE&& response)
+            const std::shared_ptr< OC::OCResourceRequest >& ocRequest, RESPONSE&& response)
     {
         auto ocResponse = response.getHandler()->buildResponse(resource);
         ocResponse->setRequestHandle(ocRequest->getRequestHandle());
@@ -78,7 +79,7 @@ namespace
     }
 
     RCSResourceAttributes getAttributesFromOCRequest(
-            std::shared_ptr< OC::OCResourceRequest > request)
+            const std::shared_ptr< OC::OCResourceRequest >& request)
     {
         return ResourceAttributesConverter::fromOCRepresentation(
                 request->getResourceRepresentation());
@@ -87,11 +88,12 @@ namespace
     template< typename HANDLER, typename RESPONSE =
             typename std::decay<HANDLER>::type::result_type >
     RESPONSE invokeHandler(RCSResourceAttributes& attrs,
-            std::shared_ptr< OC::OCResourceRequest > ocRequest, HANDLER&& handler)
+            const std::shared_ptr< OC::OCResourceRequest >& ocRequest,
+            std::shared_ptr< HANDLER > handler)
     {
         if (handler)
         {
-            return handler(RCSRequest{ ocRequest->getResourceUri() }, attrs);
+            return (*handler)(RCSRequest{ ocRequest->getResourceUri() }, attrs);
         }
 
         return RESPONSE::defaultAction();
@@ -100,7 +102,7 @@ namespace
     typedef void (RCSResourceObject::* AutoNotifyFunc)
             (bool, RCSResourceObject::AutoNotifyPolicy) const;
 
-    std::function <void ()> createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc,
+    std::function<void()> createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc,
             const RCSResourceObject& resourceObject, const RCSResourceAttributes& resourceAttributes,
             RCSResourceObject::AutoNotifyPolicy autoNotifyPolicy)
     {
@@ -337,12 +339,12 @@ namespace OIC
 
         void RCSResourceObject::setGetRequestHandler(GetRequestHandler h)
         {
-            m_getRequestHandler = std::move(h);
+            m_getRequestHandler = std::make_shared< GetRequestHandler >(std::move(h));
         }
 
         void RCSResourceObject::setSetRequestHandler(SetRequestHandler h)
         {
-            m_setRequestHandler = std::move(h);
+            m_setRequestHandler = std::make_shared< SetRequestHandler >(std::move(h));
         }
 
         void RCSResourceObject::notify() const
@@ -422,7 +424,7 @@ namespace OIC
         }
 
         OCEntityHandlerResult RCSResourceObject::entityHandler(
-                std::shared_ptr< OC::OCResourceRequest > request)
+                const std::shared_ptr< OC::OCResourceRequest >& request)
         {
             OC_LOG(WARNING, LOG_TAG, "entityHandler");
             if (!request)
@@ -457,7 +459,7 @@ namespace OIC
         }
 
         OCEntityHandlerResult RCSResourceObject::handleRequest(
-                std::shared_ptr< OC::OCResourceRequest > request)
+                const std::shared_ptr< OC::OCResourceRequest >& request)
         {
             assert(request != nullptr);
 
@@ -475,7 +477,7 @@ namespace OIC
         }
 
         OCEntityHandlerResult RCSResourceObject::handleRequestGet(
-                std::shared_ptr< OC::OCResourceRequest > request)
+                const std::shared_ptr< OC::OCResourceRequest >& request)
         {
             assert(request != nullptr);
 
@@ -518,7 +520,7 @@ namespace OIC
         }
 
         OCEntityHandlerResult RCSResourceObject::handleRequestSet(
-                std::shared_ptr< OC::OCResourceRequest > request)
+                const std::shared_ptr< OC::OCResourceRequest >& request)
         {
             assert(request != nullptr);
 
@@ -538,7 +540,7 @@ namespace OIC
         }
 
         OCEntityHandlerResult RCSResourceObject::handleObserve(
-                std::shared_ptr< OC::OCResourceRequest >)
+                const std::shared_ptr< OC::OCResourceRequest >&)
         {
             if (!isObservable())
             {
@@ -583,9 +585,9 @@ namespace OIC
             init();
         }
 
-        RCSResourceObject::LockGuard::~LockGuard()
+        RCSResourceObject::LockGuard::~LockGuard() noexcept(false)
         {
-            if (m_autoNotifyFunc) m_autoNotifyFunc();
+            if (!std::uncaught_exception() && m_autoNotifyFunc) m_autoNotifyFunc();
 
             if (m_isOwningLock)
             {
index ba441fd..33431bb 100644 (file)
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
-#include <UnitTestHelper.h>
+#include "UnitTestHelper.h"
 
-#include <RCSResourceObject.h>
+#include "RCSResourceObject.h"
 
-#include <OCPlatform.h>
+#include "OCPlatform.h"
 
 using namespace std;
 using namespace std::placeholders;
@@ -38,7 +38,7 @@ typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
 constexpr char RESOURCE_URI[]{ "a/test" };
 constexpr char RESOURCE_TYPE[]{ "resourcetype" };
 constexpr char KEY[]{ "key" };
-constexpr int value{ 100 };
+constexpr int VALUE{ 100 };
 
 TEST(ResourceObjectBuilderCreateTest, ThrowIfUriIsInvalid)
 {
@@ -122,10 +122,10 @@ TEST_F(ResourceObjectTest, AccessAttributesWithLock)
     {
         RCSResourceObject::LockGuard lock{ server };
         auto& attr = server->getAttributes();
-        attr[KEY] = value;
+        attr[KEY] = VALUE;
     }
 
-    ASSERT_EQ(value, server->getAttribute<int>(KEY));
+    ASSERT_EQ(VALUE, server->getAttribute<int>(KEY));
 }
 
 TEST_F(ResourceObjectTest, ThrowIfTryToAccessAttributesWithoutGuard)
@@ -137,10 +137,10 @@ TEST_F(ResourceObjectTest, SettingAttributesWithinGuardDoesntCauseDeadLock)
 {
     {
         RCSResourceObject::LockGuard guard{ server };
-        server->setAttribute(KEY, value);
+        server->setAttribute(KEY, VALUE);
     }
 
-    ASSERT_EQ(value, server->getAttribute<int>(KEY));
+    ASSERT_EQ(VALUE, server->getAttribute<int>(KEY));
 }
 
 TEST_F(ResourceObjectTest, SettingNestedAttributesIsSameToGettingNestedAttributes)
@@ -197,23 +197,23 @@ TEST_F(AutoNotifyTest, AutoNotifyPolicyCanBeSet)
 TEST_F(AutoNotifyTest, WithUpdatedPolicy_NeverBeNotifiedIfAttributeIsNotChanged)
 {
     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
-    server->setAttribute(KEY, value);
+    server->setAttribute(KEY, VALUE);
 
     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
             OC::OCPlatform::notifyAllObservers));
 
-    server->setAttribute(KEY, value);
+    server->setAttribute(KEY, VALUE);
 }
 
 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfAttributeIsChanged)
 {
     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
-    server->setAttribute(KEY, value);
+    server->setAttribute(KEY, VALUE);
 
     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
 
-    server->setAttribute(KEY, value + 1);
+    server->setAttribute(KEY, VALUE + 1);
 }
 
 TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfValueIsAdded)
@@ -224,7 +224,7 @@ TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfValueIsAdded)
     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
 
-    server->setAttribute(newKey, value);
+    server->setAttribute(newKey, VALUE);
 }
 
 TEST_F(AutoNotifyTest, WithNeverPolicy_NeverBeNotifiedEvenIfAttributeIsChanged)
@@ -235,13 +235,13 @@ TEST_F(AutoNotifyTest, WithNeverPolicy_NeverBeNotifiedEvenIfAttributeIsChanged)
             OC::OCPlatform::notifyAllObservers));
 
     RCSResourceObject::LockGuard lock{ server };
-    server->setAttribute(KEY, value);
+    server->setAttribute(KEY, VALUE);
 }
 
 TEST_F(AutoNotifyTest, WithUpdatePolicy_WillBeNotifiedIfAttributeIsDeleted)
 {
     server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED);
-    server->setAttribute(KEY, value);
+    server->setAttribute(KEY, VALUE);
 
     mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >(
             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
@@ -261,7 +261,7 @@ TEST_F(AutoNotifyWithGuardTest, GuardFollowsServerPolicyByDefault)
             OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
 
     RCSResourceObject::LockGuard guard{ server };
-    server->setAttribute(KEY, value);
+    server->setAttribute(KEY, VALUE);
 }
 
 TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy)
@@ -272,7 +272,7 @@ TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy)
             OC::OCPlatform::notifyAllObservers));
 
     RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::NEVER };
-    server->getAttributes()[KEY] = value;
+    server->getAttributes()[KEY] = VALUE;
 }
 
 TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed)
@@ -284,13 +284,13 @@ TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed)
 
     {
         RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::ALWAYS };
-        server->setAttribute(KEY, value);
+        server->setAttribute(KEY, VALUE);
     }
 
     mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >(
                OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK);
 
-    server->setAttribute(KEY, value);
+    server->setAttribute(KEY, VALUE);
 }
 
 
@@ -396,7 +396,7 @@ TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithRCSResponseResults)
 TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs)
 {
     constexpr int errorCode{ 1999 };
-    constexpr char value[]{ "value" };
+    constexpr char value[]{ "VALUE" };
 
     server->setSetRequestHandler(
             [](const RCSRequest&, RCSResourceAttributes&) -> RCSSetResponse
@@ -419,6 +419,7 @@ TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs)
 }
 
 
+
 class SetRequestHandlerPolicyTest: public ResourceObjectHandlingRequestTest
 {
 public:
@@ -428,14 +429,7 @@ public:
     OCRepresentation createOCRepresentation()
     {
         OCRepresentation ocRep;
-
-        vector<string> interface{"oic.if.baseline"};
-        vector<string> type{"core.light"};
-
-        ocRep.setUri(RESOURCE_URI);
-        ocRep.setResourceInterfaces(interface);
-        ocRep.setResourceTypes(type);
-
+        ocRep[KEY] = VALUE;
         return ocRep;
     }
 
@@ -460,31 +454,28 @@ TEST_F(SetRequestHandlerPolicyTest, SetRequestHandlerPolicyCanBeSet)
                 server->getSetRequestHandlerPolicy());
 }
 
-TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_NotAddedIfReceivedNewKeyValuePair)
+TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_DeniedIfKeyIsNew)
 {
-    OCRepresentation ocRep = createOCRepresentation();
-    ocRep.setValue("NewKey", value);
     server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::NEVER);
 
-    handler(createRequest(OC_REST_PUT, ocRep));
+    handler(createRequest(OC_REST_PUT, createOCRepresentation()));
 
     RCSResourceObject::LockGuard guard{ server };
-    ASSERT_FALSE((server->getAttributes()).contains("NewKey"));
+    ASSERT_FALSE(server->getAttributes().contains(KEY));
 }
 
-TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_WillBeAddedIfReceivedNewKeyValuePair)
+TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_AcceptedEvenIfKeyIsNew)
 {
-    OCRepresentation ocRep = createOCRepresentation();
-    ocRep.setValue("NewKey", value);
     server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE);
 
-    handler(createRequest(OC_REST_PUT, ocRep));
+    handler(createRequest(OC_REST_PUT, createOCRepresentation()));
 
     RCSResourceObject::LockGuard guard{ server };
-    ASSERT_TRUE((server->getAttributes()).contains("NewKey"));
+    ASSERT_TRUE(server->getAttributes().contains(KEY));
 }
 
 
+
 class ResourceObjectSynchronizationTest: public ResourceObjectHandlingRequestTest
 {
 public:
@@ -580,6 +571,7 @@ TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResourceWithRequ
 }
 
 
+
 class AttributeUpdatedListenerTest: public ResourceObjectHandlingRequestTest
 {
 public:
@@ -589,98 +581,80 @@ public:
     OCRepresentation createOCRepresentation(void)
     {
         OCRepresentation ocRep;
-
-        vector<string> interface{"oic.if.baseline"};
-        vector<string> type{"core.light"};
-
-        ocRep.setUri(RESOURCE_URI);
-        ocRep.setResourceInterfaces(interface);
-        ocRep.setResourceTypes(type);
-        ocRep[KEY] = value;
-
+        ocRep[KEY] = VALUE;
         return ocRep;
     }
 
-    void initMocks()
+protected:
+    void SetUp()
     {
-        ResourceObjectHandlingRequestTest::initMocks();
+        ResourceObjectHandlingRequestTest::SetUp();
         mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK);
+
+        server->setAttribute(KEY, 0);
     }
 };
 
-class FunctionsForAttributeUpdatedListener
+class AttributeUpdatedListener
 {
 public:
-    virtual void fCalled(const OIC::Service::RCSResourceAttributes::Value&,
-        const OIC::Service::RCSResourceAttributes::Value&)=0;
-    virtual void fNotCalled(const OIC::Service::RCSResourceAttributes::Value&,
+    virtual void onUpdated(const OIC::Service::RCSResourceAttributes::Value&,
         const OIC::Service::RCSResourceAttributes::Value&)=0;
 };
 
-TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAddedFunction)
-{
-    FunctionsForAttributeUpdatedListener *ptrMock =
-        mocks.Mock<FunctionsForAttributeUpdatedListener>();
 
-    server->setAttribute(KEY, 0);
+TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsFalseIfListenerIsNotAdded)
+{
+    ASSERT_FALSE(server->removeAttributeUpdatedListener(KEY));
+}
 
-    mocks.ExpectCall(ptrMock, FunctionsForAttributeUpdatedListener::fCalled);
+TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsAdded)
+{
+    auto listener = mocks.Mock< AttributeUpdatedListener >();
 
     server->addAttributeUpdatedListener(KEY,
-        (std::bind(&FunctionsForAttributeUpdatedListener::fCalled, ptrMock, _1, _2)));
+            std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
 
-    handler(createRequest(OC_REST_PUT, createOCRepresentation()));
+    ASSERT_TRUE(server->removeAttributeUpdatedListener(KEY));
 }
 
-TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAccordingToLastAddedFunction)
+TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAddedFunction)
 {
-    FunctionsForAttributeUpdatedListener *ptrMock =
-        mocks.Mock<FunctionsForAttributeUpdatedListener>();
+    auto listener = mocks.Mock< AttributeUpdatedListener >();
 
-    string duplicateKEY(KEY);
-    server->setAttribute(KEY, 0);
-
-    mocks.ExpectCall(ptrMock, FunctionsForAttributeUpdatedListener::fCalled);
-    mocks.NeverCall(ptrMock, FunctionsForAttributeUpdatedListener::fNotCalled);
-
-    server->addAttributeUpdatedListener(duplicateKEY,
-        (std::bind(&FunctionsForAttributeUpdatedListener::fNotCalled, ptrMock, _1, _2)));
     server->addAttributeUpdatedListener(KEY,
-        (std::bind(&FunctionsForAttributeUpdatedListener::fCalled, ptrMock, _1, _2)));
+            std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
+
+    mocks.ExpectCall(listener, AttributeUpdatedListener::onUpdated);
 
     handler(createRequest(OC_REST_PUT, createOCRepresentation()));
 }
 
-TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsNotAdded)
+TEST_F(AttributeUpdatedListenerTest, ListenerWithSameKeyOverridesPreviousOne)
 {
-    ASSERT_FALSE(server->removeAttributeUpdatedListener(KEY));
-}
+    auto first = mocks.Mock< AttributeUpdatedListener >();
+    auto second = mocks.Mock< AttributeUpdatedListener >();
 
-TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsAdded)
-{
-    FunctionsForAttributeUpdatedListener *ptrMock =
-        mocks.Mock<FunctionsForAttributeUpdatedListener>();
+    mocks.NeverCall(first, AttributeUpdatedListener::onUpdated);
+    mocks.ExpectCall(second, AttributeUpdatedListener::onUpdated);
 
     server->addAttributeUpdatedListener(KEY,
-        (std::bind(&FunctionsForAttributeUpdatedListener::fNotCalled, ptrMock, _1, _2)));
+            std::bind(&AttributeUpdatedListener::onUpdated, first, _1, _2));
+    server->addAttributeUpdatedListener(KEY,
+            std::bind(&AttributeUpdatedListener::onUpdated, second, _1, _2));
 
-    ASSERT_TRUE(server->removeAttributeUpdatedListener(KEY));
+    handler(createRequest(OC_REST_PUT, createOCRepresentation()));
 }
 
-TEST_F(AttributeUpdatedListenerTest, RemoveListenerNeverRunsRemovedFunc)
+TEST_F(AttributeUpdatedListenerTest, RemovedListenerNotBeInvoked)
 {
-    FunctionsForAttributeUpdatedListener *ptrMock =
-        mocks.Mock<FunctionsForAttributeUpdatedListener>();
+    auto listener = mocks.Mock< AttributeUpdatedListener >();
+    server->addAttributeUpdatedListener(KEY,
+            std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2));
 
-    mocks.NeverCall(ptrMock, FunctionsForAttributeUpdatedListener::fNotCalled);
+    mocks.NeverCall(listener, AttributeUpdatedListener::onUpdated);
 
-    server->setAttribute(KEY, 0);
-    server->addAttributeUpdatedListener(KEY,
-        (std::bind(&FunctionsForAttributeUpdatedListener::fNotCalled, ptrMock, _1, _2)));
     server->removeAttributeUpdatedListener(KEY);
 
     handler(createRequest(OC_REST_PUT, createOCRepresentation()));
 }
-
-
-