New observer package subscribing for error msg 31/111131/10
authorJoakim Törnqvist <joakim.tornqvist@smartoptics.com>
Wed, 27 Mar 2024 13:39:57 +0000 (13:39 +0000)
committerJoakim Törnqvist <joakim.tornqvist@smartoptics.com>
Thu, 30 Jan 2025 07:44:57 +0000 (08:44 +0100)
The EventSubscriber class is intended for tracking events of various
severity. The class provides a way of collecting error messages
for later use. The class contains convenient methods extracting the
first or last message from a given type (error, warning etc).

The class is particularly useful in the case of an iteration where it's
not uncommon for errors to occur during the iteration, although at some
point in the iteration at least one item should complete without error.

JIRA: TRNSPRTPCE-852
Change-Id: I9210afca69f516a7ef3788e854b1af4d8bbcc450
Signed-off-by: Joakim Törnqvist <joakim.tornqvist@smartoptics.com>
common/src/main/java/org/opendaylight/transportpce/common/device/observer/EventSubscriber.java [new file with mode: 0644]
common/src/main/java/org/opendaylight/transportpce/common/device/observer/Ignore.java [new file with mode: 0644]
common/src/main/java/org/opendaylight/transportpce/common/device/observer/Subscriber.java [new file with mode: 0644]
common/src/test/java/org/opendaylight/transportpce/common/device/observer/EventSubscriberTest.java [new file with mode: 0644]

diff --git a/common/src/main/java/org/opendaylight/transportpce/common/device/observer/EventSubscriber.java b/common/src/main/java/org/opendaylight/transportpce/common/device/observer/EventSubscriber.java
new file mode 100644 (file)
index 0000000..59ed6f4
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2024 Smartoptics and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.transportpce.common.device.observer;
+
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+import org.slf4j.event.Level;
+
+public class EventSubscriber implements Subscriber {
+
+    private final Map<Level, Set<String>> messages = new ConcurrentHashMap<>();
+
+    @Override
+    public void event(Level level, String message) {
+        if (message == null || message.isEmpty()) {
+            return;
+        }
+
+        if (!messages.containsKey(level)) {
+            messages.put(level, new LinkedHashSet<>());
+        }
+
+        messages.get(level).add(message);
+    }
+
+    @Override
+    public void error(String message) {
+        event(Level.ERROR, message);
+    }
+
+    @Override
+    public void warn(String message) {
+        event(Level.WARN, message);
+    }
+
+    @Override
+    public String first(Level level) {
+        return first(level, "");
+    }
+
+    @Override
+    public String first(Level level, String defaultMessage) {
+        if (!messages.containsKey(level)) {
+            return defaultMessage;
+        }
+
+        return messages.get(level).iterator().next();
+    }
+
+    @Override
+    public String first(Level level, String defaultMessage, int count) {
+        if (!messages.containsKey(level)) {
+            return defaultMessage;
+        }
+
+        return messages.get(level)
+            .stream().limit(Math.max(count, 1))
+            .collect(Collectors.joining(", "));
+    }
+
+    @Override
+    public String last(Level level) {
+        return last(level, "");
+    }
+
+    @Override
+    public String last(Level level, String defaultMessage) {
+        if (!messages.containsKey(level)) {
+            return defaultMessage;
+        }
+
+        Set<String> strings = messages.get(level);
+
+        return strings.stream().skip(strings.size() - 1).findFirst().orElse(defaultMessage);
+
+    }
+
+    @Override
+    public String[] messages(Level level) {
+
+        if (!messages.containsKey(level)) {
+            return new String[0];
+        }
+
+        Object[] arr = messages.get(level).toArray();
+
+        return Arrays.copyOf(arr, arr.length, String[].class);
+
+    }
+}
diff --git a/common/src/main/java/org/opendaylight/transportpce/common/device/observer/Ignore.java b/common/src/main/java/org/opendaylight/transportpce/common/device/observer/Ignore.java
new file mode 100644 (file)
index 0000000..9350ea0
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2024 Smartoptics and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.transportpce.common.device.observer;
+
+import org.slf4j.event.Level;
+
+public class Ignore implements Subscriber {
+
+    @Override
+    public void event(Level level, String message) {
+        return;
+    }
+
+    @Override
+    public void error(String message) {
+        return;
+    }
+
+    @Override
+    public void warn(String message) {
+        return;
+    }
+
+    @Override
+    public String first(Level level) {
+        return "";
+    }
+
+    @Override
+    public String first(Level level, String defaultMessage) {
+        return "";
+    }
+
+    @Override
+    public String first(Level level, String defaultMessage, int count) {
+        return "";
+    }
+
+    @Override
+    public String last(Level level) {
+        return "";
+    }
+
+    @Override
+    public String last(Level level, String defaultMessage) {
+        return "";
+    }
+
+    @Override
+    public String[] messages(Level level) {
+        return new String[0];
+    }
+
+}
diff --git a/common/src/main/java/org/opendaylight/transportpce/common/device/observer/Subscriber.java b/common/src/main/java/org/opendaylight/transportpce/common/device/observer/Subscriber.java
new file mode 100644 (file)
index 0000000..4b2f25e
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2024 Smartoptics and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.transportpce.common.device.observer;
+
+import org.slf4j.event.Level;
+
+/**
+ * A class wishing to 'subscribe' to, i.e. be notified about, 'events'
+ * as they happen should implement this interface.
+ *
+ * <p>A client may wish to interrogate this subscriber for the first/last
+ * event received with a particular 'level'. As an example a client
+ * may wish to know what the first or last received error message.
+ */
+public interface Subscriber {
+
+    /**
+     * Send a message to this subscriber.
+     */
+    void event(Level level, String message);
+
+    /**
+     * Send an error message to this subscriber.
+     *
+     * <p>The same as calling {@link #event(Level, String)} Level.ERROR.
+     * @param message error message
+     */
+    void error(String message);
+
+    /**
+     * Send a warning message to this subscriber.
+     *
+     * <p>The same as calling {@link #event(Level, String)} Level.WARN.
+     * @param message warning message
+     */
+    void warn(String message);
+
+    /**
+     * The first message with level caught by this subscriber.
+     */
+    String first(Level level);
+
+    /**
+     * The first message with level caught by this subscriber.
+     *
+     * <p>Return defaultMessage if no message with the specified level is found.
+     */
+    String first(Level level, String defaultMessage);
+
+    /**
+     * Return a certain number of messages with a particular message level.
+     * defaultMessage is returned in case there are no messages.
+     */
+    String first(Level level, String defaultMessage, int count);
+
+    /**
+     * The last message with level caught by this subscriber.
+     */
+    String last(Level level);
+
+    /**
+     * The last message with level caught by this subscriber.
+     *
+     * <p>Return defaultMessage if no message with the specified level is found.
+     */
+    String last(Level level, String defaultMessage);
+
+    /**
+     * All messages with level caught by subscriber
+     * in the order they were caught.
+     */
+    String[] messages(Level level);
+
+}
diff --git a/common/src/test/java/org/opendaylight/transportpce/common/device/observer/EventSubscriberTest.java b/common/src/test/java/org/opendaylight/transportpce/common/device/observer/EventSubscriberTest.java
new file mode 100644 (file)
index 0000000..646b744
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2024 Smartoptics and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.transportpce.common.device.observer;
+
+import org.junit.Assert;
+import org.junit.jupiter.api.Test;
+import org.slf4j.event.Level;
+
+class EventSubscriberTest {
+
+    @Test
+    void last() {
+        Subscriber subscriber = new EventSubscriber();
+        subscriber.event(Level.ERROR, "First");
+        subscriber.event(Level.ERROR, "Last");
+
+        Assert.assertEquals("Last", subscriber.last(Level.ERROR));
+    }
+
+    @Test
+    void empty() {
+        Subscriber subscriber = new EventSubscriber();
+
+        Assert.assertEquals("", subscriber.last(Level.ERROR));
+    }
+
+    @Test
+    void lastDefault() {
+        Subscriber subscriber = new EventSubscriber();
+
+        Assert.assertEquals("Error", subscriber.last(Level.ERROR, "Error"));
+    }
+
+    @Test
+    void firstNumber() {
+        Subscriber subscriber = new EventSubscriber();
+        subscriber.event(Level.ERROR, "First error");
+        subscriber.event(Level.WARN, "First warn");
+        subscriber.event(Level.ERROR, "Second error");
+        subscriber.event(Level.ERROR, "Third error");
+
+
+        Assert.assertEquals("First error, Second error, Third error", subscriber.first(Level.ERROR, "", 3));
+    }
+
+    @Test
+    void firstNumberContainsLessThanThree() {
+        Subscriber subscriber = new EventSubscriber();
+        subscriber.event(Level.ERROR, "First error");
+        subscriber.event(Level.WARN, "First warn");
+        subscriber.event(Level.ERROR, "Second error");
+
+
+        Assert.assertEquals("First error, Second error", subscriber.first(Level.ERROR, "", 3));
+    }
+
+    @Test
+    void firstNumberEmpty() {
+        Subscriber subscriber = new EventSubscriber();
+
+        Assert.assertEquals("Asdf", subscriber.first(Level.ERROR, "Asdf", 3));
+    }
+
+    @Test
+    void repetitiveMessages() {
+        Subscriber subscriber = new EventSubscriber();
+        subscriber.event(Level.ERROR, "First error");
+        subscriber.event(Level.ERROR, "Second error");
+        subscriber.event(Level.ERROR, "First error");
+
+        Assert.assertEquals("First error, Second error", subscriber.first(Level.ERROR, "Error", 3));
+    }
+}