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