Introduce and activate synchronous CMS event bus
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / runtime / CmsSynchronousEventBusImpl.java
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsSynchronousEventBusImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsSynchronousEventBusImpl.java
new file mode 100644 (file)
index 0000000..f7db374
--- /dev/null
@@ -0,0 +1,76 @@
+package org.argeo.cms.internal.runtime;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.argeo.api.cms.CmsEventBus;
+import org.argeo.api.cms.CmsEventSubscriber;
+import org.argeo.api.cms.CmsLog;
+
+/** A simple synchronous {@link CmsEventBus} implementation. */
+public class CmsSynchronousEventBusImpl implements CmsEventBus {
+       private final static CmsLog log = CmsLog.getLog(CmsSynchronousEventBusImpl.class);
+
+       private final Map<String, List<CmsEventSubscriber>> subscribers;
+
+       public CmsSynchronousEventBusImpl() {
+               subscribers = Collections.synchronizedMap(new HashMap<>());
+       }
+
+       @Override
+       public void sendEvent(String topic, Map<String, Object> event) {
+               List<CmsEventSubscriber> subscribersOfTopic = subscribers.get(topic);
+               if (subscribersOfTopic == null) // no one cares
+                       return;
+               synchronized (subscribersOfTopic) {
+                       for (Iterator<CmsEventSubscriber> it = subscribersOfTopic.iterator(); it.hasNext();) {
+                               CmsEventSubscriber subscriber = it.next();
+                               try {
+                                       subscriber.onEvent(topic, event);
+                               } catch (Throwable e) {
+                                       log.error("Cannot process in topic " + topic + " the event " + event + " for subscriber "
+                                                       + subscriber, e);
+                               }
+                       }
+               }
+               log.trace(() -> "Dispatched event in topic " + topic + ": " + event);
+       }
+
+       @Override
+       public synchronized void addEventSubscriber(String topic, CmsEventSubscriber eventSubscriber) {
+               if (!subscribers.containsKey(topic)) {
+                       subscribers.put(topic, new ArrayList<>());
+               }
+               subscribers.get(topic).add(eventSubscriber);
+               log.debug(() -> "Added subscriber " + eventSubscriber + " to topic " + topic);
+       }
+
+       @Override
+       public synchronized void removeEventSubscriber(String topic, CmsEventSubscriber eventSubscriber) {
+               List<CmsEventSubscriber> subscribersOfTopic = subscribers.get(topic);
+               assert subscribersOfTopic != null;
+               if (subscribersOfTopic != null) {
+                       CmsEventSubscriber removedSubscriber = null;
+                       synchronized (subscribersOfTopic) {
+                               subscribersOfTopic: for (Iterator<CmsEventSubscriber> it = subscribersOfTopic.iterator(); it
+                                               .hasNext();) {
+                                       CmsEventSubscriber subscriber = it.next();
+                                       if (subscriber == eventSubscriber) {
+                                               it.remove();
+                                               removedSubscriber = subscriber;
+                                               log.debug(() -> "Removed subscriber " + eventSubscriber + " from topic " + topic);
+                                               break subscribersOfTopic;
+                                       }
+                               }
+                       }
+                       if (removedSubscriber == null)
+                               log.warn(() -> "Subscriber " + eventSubscriber + " not found (and therefore not removed) in topic "
+                                               + topic);
+               }
+       }
+
+}