BPC frontend and backend eventing

Events can be exchanged between the frontend and backend via websocket. The following describes how:

  • an event is created in the backend

  • the event is sent to the frontend via websocket

  • the event can be intercepted in the frontend

  • a global event is sent to the backend in the frontend

Create event in the backend

An event can be created using the EventManager and sent to the frontend. The EventManager can be called by BpcServicesTracker.

The following is an example of creating an event in the backend and sending this event to the frontend.
In the example, it is assumed that the class NotificationManager has already been registered in BundleContext and therefore receives the BundleContext.

public class NotificationManager implements BpcService {
  private final BundleContext bundleContext;
  private final BpcServicesTracker<EventManager> eventManagerTracker;

  public NotificationManager(BundleContext bundleContext) {
    this.bundleContext = bundleContext;
    this.eventManagerTracker = new BpcServicesTracker<>(bundleContext, EventManager.class);
  }

  public void sendGreetingEvent() {
    try {
      // Name of event is the last part in the URI
      // In this case, event name is greetUser
      eventManagerTracker.getService().fireEvent("de/virtimo/bpc/core/notification/greetUser", DictionaryUtil.dictionaryOf(
        "message", "Hello world"
      ));
    } catch (ServiceNotFoundException ex) {
        LOG.log(Level.WARNING, "Failed to send the notification added event.", ex);
    }
  }
}

@Path("/")
public class BpcEndpoint {
    private static final Logger LOG = Logger.getLogger(BpcEndpoint.class.getName());

    private final BundleContext bundleContext;
    private BpcServicesTracker<NotificationManager> notificationManagerTracker;

    public BpcEndpoint(BundleContext bundleContext) {
      LOG.info("BpcEndpoint bundleContext=" + bundleContext);
      this.bundleContext = bundleContext;
    }

    @GET
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    public Response getInitialPage() {
      NotificationManager notificationManager = notificationManagerTracker.getService();
      notificationManager.sendGreetingEvent();
      return Response.ok().build();
    }
}

If you now call the endpoint /, the event is sent to the frontend via websocket. This event has the name greetUser.

Receive and handle events in the frontend

The event is received in the frontend as a global ExtJS event. The following shows how to intercept and handle this event in the frontend.

Declarative event handler
Ext.define("BPC.controller.WebSocketMessageController", {
  extend: "Ext.app.Controller",

  listen: {
    global: {
      "greetUser": "onGreetUser"
    }
  },

  onGreetUser: function (event) {
    const message = event.properties.message;
    alert(message.message);
  }
});
Event-Handler mit Ext.on
Ext.define("BPC.controller.WebSocketMessageController", {
  extend: "Ext.app.Controller",

  init : function () {
    Ext.on("greetUser", (event) => {
      const message = event.properties.message;
      alert(message.message);
    });
  }
});

Transmit events via websocket from the frontend to the backend

It is possible to transmit a global ExtJS event to the backend via websocket. For this purpose, the events to be forwarded to the backend should be specified in the module interface.

After the events have been specified, the frontend forwards the triggered event to the backend. This event can be received there via the EventService. By default, the event is automatically forwarded to all active clients.

As the event and the associated data are automatically distributed to all clients, handle sensitive data with care here.

The following is an example of how to specify this information.

Ext.define("demo.BpcInterface", {
  extend : "BpcCommon.BpcInterface",

  config : {
    /**
      * An array of component-xtypes which will be added to the configuration GUI for this module. They
      * will get the Ext.data.Model of the corresponding module as parameter and can be used via this.module.
      */
    moduleConfigurationComponents : [],

    /**
      * A string which points to the baseModuleView, ExtJS class, string
      */
    baseModuleView : null,

    /**
      * A string which points to the mainView, ExtJS class, string
      */
    mainView : null,

    /**
      * Array of global event names, which should be forwarded to the backend.
      */
    forwardedEvents : [
      "chat"
    ]
  }
});

// Fire global forwarded event
Ext.fireEvent("chat", {});

See also BpcInterface

Receiving and handling events in the backend

The event can be received in the backend as follows:

public public class DemoModule extends AbstractInstantiableModule {
  private static final Logger LOG = Logger.getLogger(DemoModule.class.getName());

  private final EventRegistration eventRegistration;

  public DemoModule(ModuleManager moduleManager) {
      super(moduleManager);

      this.eventRegistration = new EventRegistration(null);
  }

  public void setModuleBundle(Bundle moduleBundle) {
      super.setModuleBundle(moduleBundle);
      BundleContext bundleContext = moduleBundle.getBundleContext();

      eventRegistration.setBundleContext(bundleContext);
      eventRegistration.forClientEvents(new ChatEventHandler(bundleContext), "chat");
  }

  @Override
  public void destroy() {
      LOG.info("destroy");
      super.destroy();

      // unregister the event handlers
      eventRegistration.unregisterAllEventHandler();

      // stop the service trackers
      BpcServicesTracker.stopAll(this);
  }
  // ... other module funtioncs

  private class ChatEventHandler extends AbstractEventHandler {
      BundleContext bundleContext;
      public ChatEventHandler(BundleContext bundleContext) {
          this.bundleContext = bundleContext;
      }
      @Override
      protected void processEvent(Event event) {
          String eventTopic = event.getTopic();
          if (eventTopic.equals(CLIENT_EVENT_DOMAIN + "chat")) {
              Map<String, Object> data = (HashMap) event.getProperty("data");

              LOG.warning("A client send a message hihi: " + data.get("text"));
          }
      }
  }
}