diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py
index 95cda2c29d23c16f60889386efd4340b6ac72b76..5c956585997476d579cc0e14e0ad5eac3bb6c2b6 100644
--- a/src/context/service/ContextServiceServicerImpl.py
+++ b/src/context/service/ContextServiceServicerImpl.py
@@ -165,28 +165,29 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer
 
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
     def ListLinkIds(self, request : Empty, context : grpc.ServicerContext) -> LinkIdList:
-        return link_list_ids(self.db_engine)
+        return LinkIdList(link_ids=link_list_ids(self.db_engine))
 
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
     def ListLinks(self, request : Empty, context : grpc.ServicerContext) -> LinkList:
-        return link_list_objs(self.db_engine)
+        return LinkList(links=link_list_objs(self.db_engine))
 
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
     def GetLink(self, request : LinkId, context : grpc.ServicerContext) -> Link:
-        return link_get(self.db_engine, request)
+        return Link(**link_get(self.db_engine, request))
 
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
     def SetLink(self, request : Link, context : grpc.ServicerContext) -> LinkId:
-        link_id,updated = link_set(self.db_engine, request) # pylint: disable=unused-variable
-        #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE
-        #notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': link_id})
-        return link_id
+        link_id,updated = link_set(self.db_engine, request)
+        event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE
+        notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': link_id})
+        return LinkId(**link_id)
 
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
     def RemoveLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty:
-        deleted = link_delete(self.db_engine, request) # pylint: disable=unused-variable
-        #if deleted:
-        #    notify_event(self.messagebroker, TOPIC_LINK, EventTypeEnum.EVENTTYPE_REMOVE, {'link_id': request})
+        link_id,deleted = link_delete(self.db_engine, request)
+        if deleted:
+            event_type = EventTypeEnum.EVENTTYPE_REMOVE
+            notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': link_id})
         return Empty()
 
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
diff --git a/src/context/service/database/ConfigRule.py b/src/context/service/database/ConfigRule.py
index f64e273bfdbd1b309f4b1398309a31b1296b18ec..5f701386fa2087934088894383348ce9d00f53ad 100644
--- a/src/context/service/database/ConfigRule.py
+++ b/src/context/service/database/ConfigRule.py
@@ -59,7 +59,7 @@ def upsert_config_rules(
     if slice_uuid   is not None: stmt = stmt.where(ConfigRuleModel.slice_uuid   == slice_uuid  )
     session.execute(stmt)
 
-    updated = False
+    configrule_updates = []
     if len(config_rules) > 0:
         stmt = insert(ConfigRuleModel).values(config_rules)
         #stmt = stmt.on_conflict_do_update(
@@ -69,11 +69,9 @@ def upsert_config_rules(
         #    )
         #)
         stmt = stmt.returning(ConfigRuleModel.created_at, ConfigRuleModel.updated_at)
-        config_rule_updates = session.execute(stmt).fetchall()
-        LOGGER.warning('config_rule_updates = {:s}'.format(str(config_rule_updates)))
-        # TODO: updated = ...
+        configrule_updates = session.execute(stmt).fetchall()
 
-    return updated
+    return configrule_updates
 
 #Union_SpecificConfigRule = Union[
 #    ConfigRuleCustomModel, ConfigRuleAclModel
diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py
index 68369ac9df6f1c3bb8707452641a9d18148c6504..e40c28e699af539c8886986d18ed0aa477e00842 100644
--- a/src/context/service/database/Device.py
+++ b/src/context/service/database/Device.py
@@ -148,13 +148,14 @@ def device_set(db_engine : Engine, request : Device) -> Tuple[Dict, bool]:
         )
         stmt = stmt.returning(EndPointModel.created_at, EndPointModel.updated_at)
         endpoint_updates = session.execute(stmt).fetchall()
-        LOGGER.warning('endpoint_updates = {:s}'.format(str(endpoint_updates)))
+        updated = updated or any([(updated_at > created_at) for created_at,updated_at in endpoint_updates])
 
         session.execute(insert(TopologyDeviceModel).values(related_topologies).on_conflict_do_nothing(
             index_elements=[TopologyDeviceModel.topology_uuid, TopologyDeviceModel.device_uuid]
         ))
 
-        configrules_updated = upsert_config_rules(session, config_rules, device_uuid=device_uuid)
+        configrule_updates = upsert_config_rules(session, config_rules, device_uuid=device_uuid)
+        updated = updated or any([(updated_at > created_at) for created_at,updated_at in configrule_updates])
 
         return updated
 
diff --git a/src/context/service/database/Link.py b/src/context/service/database/Link.py
index c21dd6714a1e5f732757162987f84dd40a0ec5fe..2621e73dc62d70751c8040078968dbf4b2ad78d3 100644
--- a/src/context/service/database/Link.py
+++ b/src/context/service/database/Link.py
@@ -12,12 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import datetime, logging
 from sqlalchemy.dialects.postgresql import insert
 from sqlalchemy.engine import Engine
 from sqlalchemy.orm import Session, sessionmaker
 from sqlalchemy_cockroachdb import run_transaction
 from typing import Dict, List, Optional, Set, Tuple
-from common.proto.context_pb2 import Link, LinkId, LinkIdList, LinkList
+from common.proto.context_pb2 import Link, LinkId
 from common.method_wrappers.ServiceExceptions import NotFoundException
 from common.tools.object_factory.Link import json_link_id
 from .models.LinkModel import LinkModel, LinkEndPointModel
@@ -25,21 +26,21 @@ from .models.TopologyModel import TopologyLinkModel
 from .uuids.EndPoint import endpoint_get_uuid
 from .uuids.Link import link_get_uuid
 
-def link_list_ids(db_engine : Engine) -> LinkIdList:
+LOGGER = logging.getLogger(__name__)
+
+def link_list_ids(db_engine : Engine) -> List[Dict]:
     def callback(session : Session) -> List[Dict]:
         obj_list : List[LinkModel] = session.query(LinkModel).all()
-        #.options(selectinload(LinkModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
         return [obj.dump_id() for obj in obj_list]
-    return LinkIdList(link_ids=run_transaction(sessionmaker(bind=db_engine), callback))
+    return run_transaction(sessionmaker(bind=db_engine), callback)
 
-def link_list_objs(db_engine : Engine) -> LinkList:
+def link_list_objs(db_engine : Engine) -> List[Dict]:
     def callback(session : Session) -> List[Dict]:
         obj_list : List[LinkModel] = session.query(LinkModel).all()
-        #.options(selectinload(LinkModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
         return [obj.dump() for obj in obj_list]
-    return LinkList(links=run_transaction(sessionmaker(bind=db_engine), callback))
+    return run_transaction(sessionmaker(bind=db_engine), callback)
 
-def link_get(db_engine : Engine, request : LinkId) -> Link:
+def link_get(db_engine : Engine, request : LinkId) -> Dict:
     link_uuid = link_get_uuid(request, allow_random=False)
     def callback(session : Session) -> Optional[Dict]:
         obj : Optional[LinkModel] = session.query(LinkModel).filter_by(link_uuid=link_uuid).one_or_none()
@@ -50,14 +51,16 @@ def link_get(db_engine : Engine, request : LinkId) -> Link:
         raise NotFoundException('Link', raw_link_uuid, extra_details=[
             'link_uuid generated was: {:s}'.format(link_uuid)
         ])
-    return Link(**obj)
+    return obj
 
-def link_set(db_engine : Engine, request : Link) -> Tuple[LinkId, bool]:
+def link_set(db_engine : Engine, request : Link) -> Tuple[Dict, bool]:
     raw_link_uuid = request.link_id.link_uuid.uuid
     raw_link_name = request.name
     link_name = raw_link_uuid if len(raw_link_name) == 0 else raw_link_name
     link_uuid = link_get_uuid(request.link_id, link_name=link_name, allow_random=True)
 
+    now = datetime.datetime.utcnow()
+
     topology_uuids : Set[str] = set()
     related_topologies : List[Dict] = list()
     link_endpoints_data : List[Dict] = list()
@@ -73,23 +76,31 @@ def link_set(db_engine : Engine, request : Link) -> Tuple[LinkId, bool]:
         if endpoint_topology_uuid not in topology_uuids:
             related_topologies.append({
                 'topology_uuid': endpoint_topology_uuid,
-                'link_uuid': link_uuid,
+                'link_uuid'    : link_uuid,
             })
             topology_uuids.add(endpoint_topology_uuid)
 
     link_data = [{
-        'link_uuid': link_uuid,
-        'link_name': link_name,
+        'link_uuid' : link_uuid,
+        'link_name' : link_name,
+        'created_at': now,
+        'updated_at': now,
     }]
 
-    def callback(session : Session) -> None:
+    def callback(session : Session) -> bool:
         stmt = insert(LinkModel).values(link_data)
         stmt = stmt.on_conflict_do_update(
             index_elements=[LinkModel.link_uuid],
-            set_=dict(link_name = stmt.excluded.link_name)
+            set_=dict(
+                link_name  = stmt.excluded.link_name,
+                updated_at = stmt.excluded.updated_at,
+            )
         )
-        session.execute(stmt)
+        stmt = stmt.returning(LinkModel.created_at, LinkModel.updated_at)
+        created_at,updated_at = session.execute(stmt).fetchone()
+        updated = updated_at > created_at
 
+        # TODO: manage add/remove of endpoints; manage changes in relations with topology
         stmt = insert(LinkEndPointModel).values(link_endpoints_data)
         stmt = stmt.on_conflict_do_nothing(
             index_elements=[LinkEndPointModel.link_uuid, LinkEndPointModel.endpoint_uuid]
@@ -100,13 +111,15 @@ def link_set(db_engine : Engine, request : Link) -> Tuple[LinkId, bool]:
             index_elements=[TopologyLinkModel.topology_uuid, TopologyLinkModel.link_uuid]
         ))
 
-    run_transaction(sessionmaker(bind=db_engine), callback)
-    updated = False # TODO: improve and check if created/updated
-    return LinkId(**json_link_id(link_uuid)),updated
+        return updated
 
-def link_delete(db_engine : Engine, request : LinkId) -> bool:
+    updated = run_transaction(sessionmaker(bind=db_engine), callback)
+    return json_link_id(link_uuid),updated
+
+def link_delete(db_engine : Engine, request : LinkId) -> Tuple[Dict, bool]:
     link_uuid = link_get_uuid(request, allow_random=False)
     def callback(session : Session) -> bool:
         num_deleted = session.query(LinkModel).filter_by(link_uuid=link_uuid).delete()
         return num_deleted > 0
-    return run_transaction(sessionmaker(bind=db_engine), callback)
+    deleted = run_transaction(sessionmaker(bind=db_engine), callback)
+    return json_link_id(link_uuid),deleted
diff --git a/src/context/service/database/models/LinkModel.py b/src/context/service/database/models/LinkModel.py
index ecad019726eff8b82d4ea842d7b7596da5277e98..a13f61bf319d1298c34a64f6832399fe7ad350b8 100644
--- a/src/context/service/database/models/LinkModel.py
+++ b/src/context/service/database/models/LinkModel.py
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from sqlalchemy import Column, ForeignKey, String
+from sqlalchemy import Column, DateTime, ForeignKey, String
 from sqlalchemy.dialects.postgresql import UUID
 from sqlalchemy.orm import relationship
 from typing import Dict
@@ -23,6 +23,8 @@ class LinkModel(_Base):
 
     link_uuid  = Column(UUID(as_uuid=False), primary_key=True)
     link_name  = Column(String, nullable=False)
+    created_at = Column(DateTime)
+    updated_at = Column(DateTime)
 
     #topology_links = relationship('TopologyLinkModel', back_populates='link')
     link_endpoints = relationship('LinkEndPointModel') # lazy='joined', back_populates='link'
diff --git a/src/context/tests/test_link.py b/src/context/tests/test_link.py
index ec767f1c9bba56fe3d1f3ece4ef7b00b0951a9be..5167c41b8412183a1aa9eb929b91137afacd4532 100644
--- a/src/context/tests/test_link.py
+++ b/src/context/tests/test_link.py
@@ -12,10 +12,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import copy, grpc, pytest
-from common.proto.context_pb2 import Context, ContextId, Device, DeviceId, Empty, Link, LinkId, Topology, TopologyId
+import copy, grpc, pytest, time
+from common.proto.context_pb2 import (
+    Context, ContextEvent, ContextId, Device, DeviceEvent, DeviceId, Empty, EventTypeEnum, Link, LinkEvent, LinkId,
+    Topology, TopologyEvent, TopologyId)
 from context.client.ContextClient import ContextClient
-#from context.client.EventsCollector import EventsCollector
+from context.client.EventsCollector import EventsCollector
 from context.service.database.uuids.Link import link_get_uuid
 from .Objects import (
     CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, DEVICE_R2, DEVICE_R2_ID, LINK_R1_R2, LINK_R1_R2_ID, LINK_R1_R2_NAME,
@@ -25,12 +27,13 @@ from .Objects import (
 def test_link(context_client : ContextClient) -> None:
 
     # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
-    #events_collector = EventsCollector(
-    #    context_client, log_events_received=True,
-    #    activate_context_collector = False, activate_topology_collector = False, activate_device_collector = False,
-    #    activate_link_collector = True, activate_service_collector = False, activate_slice_collector = False,
-    #    activate_connection_collector = False)
-    #events_collector.start()
+    events_collector = EventsCollector(
+        context_client, log_events_received=True,
+        activate_context_collector = True, activate_topology_collector = True, activate_device_collector = True,
+        activate_link_collector = True, activate_service_collector = False, activate_slice_collector = False,
+        activate_connection_collector = False)
+    events_collector.start()
+    time.sleep(3)
 
     # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
     response = context_client.SetContext(Context(**CONTEXT))
@@ -45,20 +48,20 @@ def test_link(context_client : ContextClient) -> None:
     response = context_client.SetDevice(Device(**DEVICE_R2))
     device_r2_uuid = response.device_uuid.uuid
 
-    # events = events_collector.get_events(block=True, count=4)
-    # assert isinstance(events[0], ContextEvent)
-    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[0].context_id.context_uuid.uuid == context_uuid
-    # assert isinstance(events[1], TopologyEvent)
-    # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[1].topology_id.context_id.context_uuid.uuid == context_uuid
-    # assert events[1].topology_id.topology_uuid.uuid == topology_uuid
-    # assert isinstance(events[2], DeviceEvent)
-    # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[2].device_id.device_uuid.uuid == device_r1_uuid
-    # assert isinstance(events[3], DeviceEvent)
-    # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[3].device_id.device_uuid.uuid == device_r2_uuid
+    events = events_collector.get_events(block=True, count=4, timeout=1.0)
+    assert isinstance(events[0], ContextEvent)
+    assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[0].context_id.context_uuid.uuid == context_uuid
+    assert isinstance(events[1], TopologyEvent)
+    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[1].topology_id.context_id.context_uuid.uuid == context_uuid
+    assert events[1].topology_id.topology_uuid.uuid == topology_uuid
+    assert isinstance(events[2], DeviceEvent)
+    assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[2].device_id.device_uuid.uuid == device_r1_uuid
+    assert isinstance(events[3], DeviceEvent)
+    assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[3].device_id.device_uuid.uuid == device_r2_uuid
 
     # ----- Get when the object does not exist -------------------------------------------------------------------------
     link_id = LinkId(**LINK_R1_R2_ID)
@@ -81,10 +84,10 @@ def test_link(context_client : ContextClient) -> None:
     assert response.link_uuid.uuid == link_uuid
 
     # ----- Check create event -----------------------------------------------------------------------------------------
-    #event = events_collector.get_event(block=True)
-    #assert isinstance(event, LinkEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    #assert event.link_id.link_uuid.uuid == link_uuid
+    event = events_collector.get_event(block=True, timeout=1.0)
+    assert isinstance(event, LinkEvent)
+    assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert event.link_id.link_uuid.uuid == link_uuid
 
     # ----- Get when the object exists ---------------------------------------------------------------------------------
     response = context_client.GetLink(LinkId(**LINK_R1_R2_ID))
@@ -111,10 +114,10 @@ def test_link(context_client : ContextClient) -> None:
     assert response.link_uuid.uuid == link_uuid
 
     # ----- Check update event -----------------------------------------------------------------------------------------
-    #event = events_collector.get_event(block=True)
-    #assert isinstance(event, LinkEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    #assert event.link_id.link_uuid.uuid == link_uuid
+    event = events_collector.get_event(block=True, timeout=1.0)
+    assert isinstance(event, LinkEvent)
+    assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    assert event.link_id.link_uuid.uuid == link_uuid
 
     # ----- Get when the object is modified ----------------------------------------------------------------------------
     response = context_client.GetLink(LinkId(**LINK_R1_R2_ID))
@@ -133,20 +136,6 @@ def test_link(context_client : ContextClient) -> None:
     assert response.links[0].name == new_link_name
     assert len(response.links[0].link_endpoint_ids) == 2
 
-    # ----- Create object relation -------------------------------------------------------------------------------------
-    #TOPOLOGY_WITH_LINK = copy.deepcopy(TOPOLOGY)
-    #TOPOLOGY_WITH_LINK['link_ids'].append(LINK_R1_R2_ID)
-    #response = context_client.SetTopology(Topology(**TOPOLOGY_WITH_LINK))
-    #assert response.context_id.context_uuid.uuid == context_uuid
-    #assert response.topology_uuid.uuid == topology_uuid
-
-    # ----- Check update event -----------------------------------------------------------------------------------------
-    #event = events_collector.get_event(block=True)
-    #assert isinstance(event, TopologyEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    #assert response.context_id.context_uuid.uuid == context_uuid
-    #assert response.topology_uuid.uuid == topology_uuid
-
     # ----- Check relation was created ---------------------------------------------------------------------------------
     response = context_client.GetTopology(TopologyId(**TOPOLOGY_ID))
     assert response.topology_id.context_id.context_uuid.uuid == context_uuid
@@ -161,10 +150,10 @@ def test_link(context_client : ContextClient) -> None:
     context_client.RemoveLink(LinkId(**LINK_R1_R2_ID))
 
     # ----- Check remove event -----------------------------------------------------------------------------------------
-    #event = events_collector.get_event(block=True)
-    #assert isinstance(event, LinkEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    #assert event.link_id.link_uuid.uuid == link_uuid
+    event = events_collector.get_event(block=True, timeout=1.0)
+    assert isinstance(event, LinkEvent)
+    assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert event.link_id.link_uuid.uuid == link_uuid
 
     # ----- List after deleting the object -----------------------------------------------------------------------------
     response = context_client.ListLinkIds(Empty())
@@ -187,20 +176,20 @@ def test_link(context_client : ContextClient) -> None:
     context_client.RemoveTopology(TopologyId(**TOPOLOGY_ID))
     context_client.RemoveContext(ContextId(**CONTEXT_ID))
 
-    #events = events_collector.get_events(block=True, count=4)
-    #assert isinstance(events[0], DeviceEvent)
-    #assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    #assert events[0].device_id.device_uuid.uuid == device_r1_uuid
-    #assert isinstance(events[1], DeviceEvent)
-    #assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    #assert events[1].device_id.device_uuid.uuid == device_r2_uuid
-    #assert isinstance(events[2], TopologyEvent)
-    #assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    #assert events[2].topology_id.context_id.context_uuid.uuid == context_uuid
-    #assert events[2].topology_id.topology_uuid.uuid == topology_uuid
-    #assert isinstance(events[3], ContextEvent)
-    #assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    #assert events[3].context_id.context_uuid.uuid == context_uuid
+    events = events_collector.get_events(block=True, count=4, timeout=1.0)
+    assert isinstance(events[0], DeviceEvent)
+    assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[0].device_id.device_uuid.uuid == device_r1_uuid
+    assert isinstance(events[1], DeviceEvent)
+    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[1].device_id.device_uuid.uuid == device_r2_uuid
+    assert isinstance(events[2], TopologyEvent)
+    assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[2].topology_id.context_id.context_uuid.uuid == context_uuid
+    assert events[2].topology_id.topology_uuid.uuid == topology_uuid
+    assert isinstance(events[3], ContextEvent)
+    assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[3].context_id.context_uuid.uuid == context_uuid
 
     # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
-    #events_collector.stop()
+    events_collector.stop()