BPC Frontend- und Backend-Eventing

Events lassen sich zwischen Frontend und Backend über Websocket austauschen. Nachfolgend wird beschrieben, wie:

  • ein Event im Backend erstellt wird

  • das Event über Websocket ans Frontend gesendet wird

  • das Event im Frontend abgefangen werden kann

  • ein globales Event im Frontend ans Backend übermittelt wird

Event im Backend erstellen

Ein Event lässt sich mittels des EventManager`s erstellen und an das Frontend senden. Der `EventManager kann durch BpcServicesTracker aufgerufen werden.

Nachfolgend ist ein Beispiel zur Erstellung vom Event im Backend und zum Senden dieses Events ans Frontend.
Im Beispiel wird angenommen, dass die Klasse NotificationManager schon im BundleContext registriert wurde und erhält daher das BundleContext übergeben.

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();
    }
}

Wenn man jetzt den Endpunkt / aufruft, wird das Event an Frontend über Websocket gesendet. Dieses Event hat den Name greetUser.

Events im Frontend empfangen und behandeln

Das Event wird im Frontend als globales ExtJS-Event empfangen. Nachfolgend wird gezeigt, wie man dieses Event im Frontend abfängt und behandelt.

Deklarativer 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);
    });
  }
});

Events über Websocket vom Frontend zum Backend übermitteln

Es besteht die Möglichkeit, ein globales ExtJS-Event zum Backend über Websocket zu übermittelt. Dazu soll im Modul-Interface angegeben werden, welche Events ans Backend weitergeleitet werden sollen.

Nachdem die Events angegeben wurden, leitet das Frontend das ausgelöste Event zum Backend. Dieses Event kann dort über den EventService empfangen werden. Standardmäßig wird das Event automatisch an alle aktiven Clients weitergeleitet.

Da das Event und die dazugehörigen Daten automatisch an alle Clients verteilt werden, gehen Sie hier behutsam mit sensiblen Daten um.

Nachfolgend ist ein Beispiel, wie man diese Information angibt.

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", {});

Siehe auch BpcInterface

Events im Backend empfangen und behandeln

Das Event lässt sich im Backend wie folgt empfangen:

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"));
          }
      }
  }
}