Move liblttng-ust-java* to 'src/lib/'
[lttng-ust.git] / src / lib / lttng-ust-java-agent / java / lttng-ust-agent-common / org / lttng / ust / agent / filter / FilterChangeNotifier.java
diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/FilterChangeNotifier.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/FilterChangeNotifier.java
new file mode 100644 (file)
index 0000000..e1c96e1
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2015 EfficiOS Inc.
+ * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com>
+ */
+
+package org.lttng.ust.agent.filter;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.lttng.ust.agent.session.EventRule;
+
+/**
+ * Singleton class managing the filter notifications.
+ *
+ * Applications can register a {@link IFilterChangeListener} to be notified when
+ * event filtering rules change in the tracing sessions.
+ *
+ * @author Alexandre Montplaisir
+ */
+public final class FilterChangeNotifier {
+
+       /** Lazy-loaded singleton instance object */
+       private static FilterChangeNotifier instance = null;
+
+       private final Map<EventRule, Integer> enabledEventRules = new HashMap<EventRule, Integer>();
+       private final Collection<IFilterChangeListener> registeredListeners = new LinkedList<IFilterChangeListener>();
+
+
+       /**
+        * Private constructor, singleton class should not be instantiated directly.
+        */
+       private FilterChangeNotifier() {
+       }
+
+       /**
+        * Get the singleton instance, initializing it if needed.
+        *
+        * @return The singleton instance
+        */
+       public static synchronized FilterChangeNotifier getInstance() {
+               if (instance == null) {
+                       instance = new FilterChangeNotifier();
+               }
+               return instance;
+       }
+
+       /**
+        * Notify the filter manager that a new rule was enabled in a tracing
+        * session ("lttng enable-event ...")
+        *
+        * This is meant to be called by the LTTng Agent only. External Java
+        * applications should not call this.
+        *
+        * @param rule
+        *            The rule that was added
+        */
+       public synchronized void addEventRule(EventRule rule) {
+               Integer count = enabledEventRules.get(rule);
+               if (count == null) {
+                       /*
+                        * This is the first instance of this rule being enabled. Add it to
+                        * the map and send notifications to the registered notifiers.
+                        */
+                       enabledEventRules.put(rule, Integer.valueOf(1));
+                       notifyForAddedRule(rule);
+                       return;
+               }
+               if (count.intValue() <= 0) {
+                       /* It should not have been in the map! */
+                       throw new IllegalStateException();
+               }
+               /*
+                * This exact event rule was already enabled, just increment its
+                * refcount without sending notifications
+                */
+               enabledEventRules.put(rule, Integer.valueOf(count.intValue() + 1));
+       }
+
+       /**
+        * Notify the filter manager that an event name was disabled in the tracing
+        * sessions ("lttng disable-event ...").
+        *
+        * The "disable-event" only specifies an event name. This means all the
+        * rules containing this event name are to be disabled.
+        *
+        * This is meant to be called by the LTTng Agent only. External Java
+        * applications should not call this.
+        *
+        * @param eventName
+        *            The event name to disable
+        */
+       public synchronized void removeEventRules(String eventName) {
+               List<EventRule> rulesToRemove = new LinkedList<EventRule>();
+
+               for (EventRule eventRule : enabledEventRules.keySet()) {
+                       if (eventRule.getEventName().equals(eventName)) {
+                               rulesToRemove.add(eventRule);
+                       }
+               }
+               /*
+                * We cannot modify the map while iterating on it. We have to do the
+                * removal separately from the iteration above.
+                */
+               for (EventRule rule : rulesToRemove) {
+                       removeEventRule(rule);
+               }
+       }
+
+       private synchronized void removeEventRule(EventRule eventRule) {
+               Integer count = enabledEventRules.get(eventRule);
+               if (count == null || count.intValue() <= 0) {
+                       /*
+                        * We were asked us to disable an event rule that was not enabled
+                        * previously. Command error?
+                        */
+                       throw new IllegalStateException();
+               }
+               if (count.intValue() == 1) {
+                       /*
+                        * This is the last instance of this event rule being disabled,
+                        * remove it from the map and send notifications of this rule being
+                        * gone.
+                        */
+                       enabledEventRules.remove(eventRule);
+                       notifyForRemovedRule(eventRule);
+                       return;
+               }
+               /*
+                * Other sessions/daemons are still looking for this event rule, simply
+                * decrement its refcount, and do not send notifications.
+                */
+               enabledEventRules.put(eventRule, Integer.valueOf(count.intValue() - 1));
+
+       }
+
+       /**
+        * Register a new listener to the manager.
+        *
+        * @param listener
+        *            The listener to add
+        */
+       public synchronized void registerListener(IFilterChangeListener listener) {
+               registeredListeners.add(listener);
+
+               /* Send the current rules to the new listener ("statedump") */
+               for (EventRule rule : enabledEventRules.keySet()) {
+                       listener.eventRuleAdded(rule);
+               }
+       }
+
+       /**
+        * Unregister a listener from the manager.
+        *
+        * @param listener
+        *            The listener to remove
+        */
+       public synchronized void unregisterListener(IFilterChangeListener listener) {
+               registeredListeners.remove(listener);
+       }
+
+       private void notifyForAddedRule(final EventRule rule) {
+               for (IFilterChangeListener notifier : registeredListeners) {
+                       notifier.eventRuleAdded(rule);
+               }
+       }
+
+       private void notifyForRemovedRule(final EventRule rule) {
+               for (IFilterChangeListener notifier : registeredListeners) {
+                       notifier.eventRuleRemoved(rule);
+               }
+       }
+}
This page took 0.025975 seconds and 4 git commands to generate.