1a675876772456e087eeeae9e1d35f8c5a44279a
[lttng-ust.git] / liblttng-ust-java-agent / java / lttng-ust-agent-common / org / lttng / ust / agent / filter / FilterChangeNotifier.java
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 }
This page took 0.03184 seconds and 3 git commands to generate.