Commit | Line | Data |
---|---|---|
4fb826b1 | 1 | /* |
c0c0989a | 2 | * SPDX-License-Identifier: LGPL-2.1-only |
4fb826b1 | 3 | * |
c0c0989a MJ |
4 | * Copyright (C) 2015 EfficiOS Inc. |
5 | * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com> | |
4fb826b1 AM |
6 | */ |
7 | ||
8 | package org.lttng.ust.agent.filter; | |
9 | ||
10 | import java.util.Collection; | |
11 | import java.util.HashMap; | |
12 | import java.util.LinkedList; | |
13 | import java.util.List; | |
14 | import java.util.Map; | |
15 | ||
16 | import org.lttng.ust.agent.session.EventRule; | |
17 | ||
18 | /** | |
19 | * Singleton class managing the filter notifications. | |
20 | * | |
21 | * Applications can register a {@link IFilterChangeListener} to be notified when | |
22 | * event filtering rules change in the tracing sessions. | |
23 | * | |
24 | * @author Alexandre Montplaisir | |
25 | */ | |
26 | public final class FilterChangeNotifier { | |
27 | ||
28 | /** Lazy-loaded singleton instance object */ | |
29 | private static FilterChangeNotifier instance = null; | |
30 | ||
31 | private final Map<EventRule, Integer> enabledEventRules = new HashMap<EventRule, Integer>(); | |
32 | private final Collection<IFilterChangeListener> registeredListeners = new LinkedList<IFilterChangeListener>(); | |
33 | ||
34 | ||
35 | /** | |
36 | * Private constructor, singleton class should not be instantiated directly. | |
37 | */ | |
38 | private FilterChangeNotifier() { | |
39 | } | |
40 | ||
41 | /** | |
42 | * Get the singleton instance, initializing it if needed. | |
43 | * | |
44 | * @return The singleton instance | |
45 | */ | |
46 | public static synchronized FilterChangeNotifier getInstance() { | |
47 | if (instance == null) { | |
48 | instance = new FilterChangeNotifier(); | |
49 | } | |
50 | return instance; | |
51 | } | |
52 | ||
53 | /** | |
54 | * Notify the filter manager that a new rule was enabled in a tracing | |
55 | * session ("lttng enable-event ...") | |
56 | * | |
57 | * This is meant to be called by the LTTng Agent only. External Java | |
58 | * applications should not call this. | |
59 | * | |
60 | * @param rule | |
61 | * The rule that was added | |
62 | */ | |
63 | public synchronized void addEventRule(EventRule rule) { | |
64 | Integer count = enabledEventRules.get(rule); | |
65 | if (count == null) { | |
66 | /* | |
67 | * This is the first instance of this rule being enabled. Add it to | |
68 | * the map and send notifications to the registered notifiers. | |
69 | */ | |
70 | enabledEventRules.put(rule, Integer.valueOf(1)); | |
71 | notifyForAddedRule(rule); | |
72 | return; | |
73 | } | |
74 | if (count.intValue() <= 0) { | |
75 | /* It should not have been in the map! */ | |
76 | throw new IllegalStateException(); | |
77 | } | |
78 | /* | |
79 | * This exact event rule was already enabled, just increment its | |
80 | * refcount without sending notifications | |
81 | */ | |
82 | enabledEventRules.put(rule, Integer.valueOf(count.intValue() + 1)); | |
83 | } | |
84 | ||
85 | /** | |
86 | * Notify the filter manager that an event name was disabled in the tracing | |
87 | * sessions ("lttng disable-event ..."). | |
88 | * | |
89 | * The "disable-event" only specifies an event name. This means all the | |
90 | * rules containing this event name are to be disabled. | |
91 | * | |
92 | * This is meant to be called by the LTTng Agent only. External Java | |
93 | * applications should not call this. | |
94 | * | |
95 | * @param eventName | |
96 | * The event name to disable | |
97 | */ | |
98 | public synchronized void removeEventRules(String eventName) { | |
99 | List<EventRule> rulesToRemove = new LinkedList<EventRule>(); | |
100 | ||
101 | for (EventRule eventRule : enabledEventRules.keySet()) { | |
102 | if (eventRule.getEventName().equals(eventName)) { | |
103 | rulesToRemove.add(eventRule); | |
104 | } | |
105 | } | |
106 | /* | |
107 | * We cannot modify the map while iterating on it. We have to do the | |
108 | * removal separately from the iteration above. | |
109 | */ | |
110 | for (EventRule rule : rulesToRemove) { | |
111 | removeEventRule(rule); | |
112 | } | |
113 | } | |
114 | ||
115 | private synchronized void removeEventRule(EventRule eventRule) { | |
116 | Integer count = enabledEventRules.get(eventRule); | |
117 | if (count == null || count.intValue() <= 0) { | |
118 | /* | |
119 | * We were asked us to disable an event rule that was not enabled | |
120 | * previously. Command error? | |
121 | */ | |
122 | throw new IllegalStateException(); | |
123 | } | |
124 | if (count.intValue() == 1) { | |
125 | /* | |
126 | * This is the last instance of this event rule being disabled, | |
127 | * remove it from the map and send notifications of this rule being | |
128 | * gone. | |
129 | */ | |
130 | enabledEventRules.remove(eventRule); | |
131 | notifyForRemovedRule(eventRule); | |
132 | return; | |
133 | } | |
134 | /* | |
135 | * Other sessions/daemons are still looking for this event rule, simply | |
136 | * decrement its refcount, and do not send notifications. | |
137 | */ | |
138 | enabledEventRules.put(eventRule, Integer.valueOf(count.intValue() - 1)); | |
139 | ||
140 | } | |
141 | ||
142 | /** | |
143 | * Register a new listener to the manager. | |
144 | * | |
145 | * @param listener | |
146 | * The listener to add | |
147 | */ | |
148 | public synchronized void registerListener(IFilterChangeListener listener) { | |
149 | registeredListeners.add(listener); | |
150 | ||
151 | /* Send the current rules to the new listener ("statedump") */ | |
152 | for (EventRule rule : enabledEventRules.keySet()) { | |
153 | listener.eventRuleAdded(rule); | |
154 | } | |
155 | } | |
156 | ||
157 | /** | |
158 | * Unregister a listener from the manager. | |
159 | * | |
160 | * @param listener | |
161 | * The listener to remove | |
162 | */ | |
163 | public synchronized void unregisterListener(IFilterChangeListener listener) { | |
164 | registeredListeners.remove(listener); | |
165 | } | |
166 | ||
167 | private void notifyForAddedRule(final EventRule rule) { | |
168 | for (IFilterChangeListener notifier : registeredListeners) { | |
169 | notifier.eventRuleAdded(rule); | |
170 | } | |
171 | } | |
172 | ||
173 | private void notifyForRemovedRule(final EventRule rule) { | |
174 | for (IFilterChangeListener notifier : registeredListeners) { | |
175 | notifier.eventRuleRemoved(rule); | |
176 | } | |
177 | } | |
178 | } |