Event Service

Concepts

The JS OSGi platform provided by map.apps implements the OSGi EventAdmin Service Specification (specified in the OSGi Compendium Specification) and slightly extends it for simpler usage within bundles.

The EventAdminService (referenced as Event Service in the following) is used to broadcast messages as topics within the OSGi runtime. OSGi Services which implement the EventHandler interface are informed about these messages.

The Event Service is one of the core services that are required to build independent bundles that can interact with each other.

Broadcasting Messages

The Event Service is part of the system bundle and registered as ct.framework.api.EventService. It can be referenced by using the following definition inside a component:

Component Reference
"references": [{
  "name": "_eventService",
  "providing": "ct.framework.api.EventService"
}]

The Event Service provides two methods to broadcast an event:

  1. sendEvent synchronously broadcasts a message to the EventListeners.

    sendEvent
    // in your component code do:
    this._eventService.sendEvent("my/topic/ACTION",{propA : "event property A"});
  2. postEvent asynchronously broadcasts a message to the EventListeners. This is the recommended way of using the Event Service.

    postEvent
    // in your componente code do:
    this._eventService.postEvent("my/topic/ACTION",{ propA: "event property A"});

Listening for Messages

An OSGi service that wants to listen to messages broadcasted by the Event Service must be registered as ct.framework.api.EventHandler and provide the service property Event-Topics.

The following kinds of listener registrations using the manifest.json file are available:

Classic Notation
// Registers a an event handler to listen on messages of topic "ct/map/EXTENT_CHANGE".
{
  "name": "MyEventHandler",
  "provides": ["ct.framework.api.EventHandler"],
  "properties":{
    "Event-Topics": ["ct/map/EXTENT_CHANGE"]
  }
}

// Service Implementation
export default class{
  // 'handleEvent' is the default method name called by the Event Service to inform the listener.
  // @param evt {apprt/event/Event} the broadcasted event
  handleEvent(event){
    // topic = 'ct/map/EXTENT_CHANGE'
    let topic = event.getTopic();

    // reason is 'EXTENT_CHANGE' (the last topic part)
    let reason = event.getTopicReason();

    let extent = event.getProperty("extent");
    // do something with the extent
  }
}
Classic Notation with filter
// Registers an event handler to listen on messages of all topics starting with "ct/tool/ACTIVATE/".
// It demonstrates that you can use the wildcard '*' at the end of a topic path
// to listen on all events use the topic name '*'.
// The "Event-Filter" property allows filtering messages by their properties.
// In this example the event handler is only informed about event messages if the message has the property "toolId" with the value 'toolA' or 'toolB'
{
  "name": "MyEventHandler",
  "provides": ["ct.framework.api.EventHandler"],
  "properties":{
    "Event-Topics": ["ct/tool/ACTIVATE/*"],
    "Event-Filter": ["(|(toolId=toolA)(toolId=toolB))"]
  }
}

// Service implementation
export default class{
  // 'handleEvent' is the default method name called by the Event Service to inform the listener.
  // @param evt {apprt/event/Event} the broadcasted event
  handleEvent(event){
    let toolId = event.getProperty("toolId");
    // do something with the ID
  }
}
Topic Object Notation
// Here the topic object notation is shown.
// It allows to map topics to individual methods in the EventHandler instance.
{
  "name": "MyEventHandler",
  "provides": ["ct.framework.api.EventHandler"],
  "properties":{
    "Event-Topics": [{
      "topic":"ct/tool/ACTIVATE/toolA",
      "method":"_handleActivationOfToolA"
    }]
  }
}

// Service implementation
export default class{
  // @param evt {apprt/event/Event} the broadcasted event
  _handleActivationOfToolA(event){
    var toolId = event.getProperty("toolId");
    // do something with the ID
  }
}
Topic Object Notation with multiple topics to one method
// This example demonstrates the use of the topic object notation to map multiple topics to one method.
{
  "name": "MyEventHandler",
  "provides": ["ct.framework.api.EventHandler"],
  "properties":{
    "Event-Topics": [{
      "topic":["ct/tool/ACTIVATE/toolA","ct/tool/ACTIVATE/toolB"],
      "method":"_handleActivationOfTool"
    }]
  }
}

// Service implementation
export default class{
  // @param evt {apprt/event/Event} the broadcasted event
  _handleActivationOfTool(event){
    var toolId = event.getProperty("toolId");
    // do something with the ID
  }
}
Topic Object Notation with filter
// This sample shows the usage of the topic object notation and the direct configuration of a filter within this topic object
{
  "name": "MyEventHandler",
  "provides": ["ct.framework.api.EventHandler"],
  "properties":{
    "Event-Topics": [{
      "topic":"ct/tool/ACTIVATE/*",
      "method":"_handleActivationOfToolA",
      "filter" : "(toolId=toolA)"
    }]
  }
}

// Service implementation
export default class{
  // @param evt {apprt/event/Event} the broadcasted event
  _handleActivationOfToolA(event){
    var toolId = event.getProperty("toolId");
    // do something with the ID
  }
}
Topic Object Notation with parameter binding
// This sample shows the usage of the topic object notation with the pre-configuration of handler method params
{
  "name": "MyEventHandler",
  "provides": ["ct.framework.api.EventHandler"],
  "properties":{
    "Event-Topics": [{
      "topic":"ct/tool/ACTIVATE/toolA",
      "method":"_switchActivate",
      "params" : [true]
    },
    {
      "topic":"ct/tool/DEACTIVATE/toolA",
      "method":"_switchActivate",
      "params" : [false]
    }]
  }
}

// Service implementation (does not know that it is an EventHandler)
export default class{
  // @param flag {boolean} a flag provided by the configuration
  _switchActivate(active /*, event // is still provided */){
    if (active){
      // do if active
    }else{
      // do if not active
    }
  }
}