1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.log4j.plugins;
18
19 import org.apache.log4j.spi.LoggerRepository;
20 import org.apache.log4j.spi.LoggerRepositoryEventListener;
21 import org.apache.log4j.spi.LoggerRepositoryEx;
22
23 import java.util.*;
24
25
26 /**
27 * This is a registry for Plugin instances. It provides methods to
28 * start and stop plugin objects individually and to stop all
29 * plugins for a repository.
30 *
31 * @author Mark Womack
32 * @author Paul Smith
33 */
34 public final class PluginRegistry {
35 /**
36 * The pluginMap is keyed by plugin name and contains plugins as values.
37 * key=plugin.getName, value=plugin
38 */
39 private final Map<String, Plugin> pluginMap;
40 /**
41 * Logger repository.
42 */
43 private final LoggerRepositoryEx loggerRepository;
44
45 /**
46 * the listener used to listen for repository events.
47 */
48 private final RepositoryListener listener = new RepositoryListener();
49 /**
50 * List of listeners.
51 */
52 private final List listenerList =
53 Collections.synchronizedList(new ArrayList());
54
55 /**
56 * Creates a new instance.
57 *
58 * @param repository logger repository.
59 */
60 public PluginRegistry(final LoggerRepositoryEx repository) {
61 super();
62 pluginMap = new HashMap<>();
63 this.loggerRepository = repository;
64 this.loggerRepository.addLoggerRepositoryEventListener(listener);
65 }
66
67 /**
68 * Get logger repository.
69 *
70 * @return logger repository.
71 */
72 public LoggerRepositoryEx getLoggerRepository() {
73 return loggerRepository;
74 }
75
76
77 /**
78 * Returns true if the specified name is already taken by
79 * an existing Plugin registered within the scope of the specified
80 * LoggerRepository.
81 *
82 * @param name The name to check the repository for
83 * @return true if the name is already in use, otherwise false
84 */
85 public boolean pluginNameExists(final String name) {
86 synchronized (pluginMap) {
87 return pluginMap.containsKey(name);
88 }
89 }
90
91
92 /**
93 * Adds a plugin to the plugin registry.
94 * If a plugin with the same name exists
95 * already, it is shutdown and removed.
96 *
97 * @param plugin the plugin to add.
98 */
99 public void addPlugin(final Plugin plugin) {
100 // put plugin into the repository's reciever map
101 synchronized (pluginMap) {
102 String name = plugin.getName();
103
104 // make sure the plugin has reference to repository
105 plugin.setLoggerRepository(getLoggerRepository());
106
107 Plugin existingPlugin = pluginMap.get(name);
108 if (existingPlugin != null) {
109 existingPlugin.shutdown();
110 }
111
112 // put the new plugin into the map
113 pluginMap.put(name, plugin);
114 firePluginStarted(plugin);
115 }
116 }
117
118
119 /**
120 * Calls the pluginStarted method on every registered PluginListener.
121 *
122 * @param plugin The plugin that has been started.
123 */
124 private void firePluginStarted(final Plugin plugin) {
125 PluginEvent e = null;
126 synchronized (listenerList) {
127 for (Object aListenerList : listenerList) {
128 PluginListener l = (PluginListener) aListenerList;
129 if (e == null) {
130 e = new PluginEvent(plugin);
131 }
132 l.pluginStarted(e);
133 }
134 }
135 }
136
137
138 /**
139 * Calls the pluginStopped method for every registered PluginListner.
140 *
141 * @param plugin The plugin that has been stopped.
142 */
143 private void firePluginStopped(final Plugin plugin) {
144 PluginEvent e = null;
145 synchronized (listenerList) {
146 for (Object aListenerList : listenerList) {
147 PluginListener l = (PluginListener) aListenerList;
148 if (e == null) {
149 e = new PluginEvent(plugin);
150 }
151 l.pluginStopped(e);
152 }
153 }
154 }
155
156
157 /**
158 * Returns all the plugins for a given repository.
159 *
160 * @return List list of plugins from the repository.
161 */
162 public List<Plugin> getPlugins() {
163 synchronized (pluginMap) {
164 List<Plugin> pluginList = new ArrayList<>(pluginMap.size());
165
166 pluginList.addAll(pluginMap.values());
167 return pluginList;
168 }
169 }
170
171
172 /**
173 * Returns all the plugins for a given repository that are instances
174 * of a certain class.
175 *
176 * @param pluginClass the class the plugin must implement to be selected.
177 * @return List list of plugins from the repository.
178 */
179 public List getPlugins(final Class pluginClass) {
180 synchronized (pluginMap) {
181 List pluginList = new ArrayList(pluginMap.size());
182
183 for (Object plugin : pluginMap.values()) {
184 if (pluginClass.isInstance(plugin)) {
185 pluginList.add(plugin);
186 }
187 }
188 return pluginList;
189 }
190 }
191
192
193 /**
194 * Stops a plugin by plugin name and repository.
195 *
196 * @param pluginName the name of the plugin to stop.
197 * @return Plugin the plugin, if stopped, or null if the
198 * the plugin was not found in the registry.
199 */
200 public Plugin stopPlugin(final String pluginName) {
201 synchronized (pluginMap) {
202 Plugin plugin = pluginMap.get(pluginName);
203
204 if (plugin == null) {
205 return null;
206 }
207
208 // shutdown the plugin
209 plugin.shutdown();
210
211 // remove it from the plugin map
212 pluginMap.remove(pluginName);
213 firePluginStopped(plugin);
214
215 // return it for future use
216 return plugin;
217 }
218 }
219
220 /**
221 * Stops all plugins in the given logger repository.
222 */
223 public void stopAllPlugins() {
224 synchronized (pluginMap) {
225 // remove the listener for this repository
226 loggerRepository.removeLoggerRepositoryEventListener(listener);
227
228 for (Object o : pluginMap.values()) {
229 Plugin plugin = (Plugin) o;
230 plugin.shutdown();
231 firePluginStopped(plugin);
232 }
233 }
234 }
235
236
237 /**
238 * Adds a PluginListener to this registry to be notified
239 * of PluginEvents.
240 *
241 * @param l PluginListener to add to this registry
242 */
243 public void addPluginListener(final PluginListener l) {
244 listenerList.add(l);
245 }
246
247
248 /**
249 * Removes a particular PluginListener from this registry
250 * such that it will no longer be notified of PluginEvents.
251 *
252 * @param l PluginListener to remove
253 */
254 public void removePluginListener(final PluginListener l) {
255 listenerList.remove(l);
256 }
257
258 /**
259 * Internal class used to handle listener events from repositories.
260 */
261 private class RepositoryListener implements LoggerRepositoryEventListener {
262 /**
263 * Stops all plugins associated with the repository being reset.
264 *
265 * @param repository the repository that was reset.
266 */
267 public void configurationResetEvent(final LoggerRepository repository) {
268 PluginRegistry.this.stopAllPlugins();
269 }
270
271
272 /**
273 * Called when the repository configuration is changed.
274 *
275 * @param repository the repository that was changed.
276 */
277 public void configurationChangedEvent(
278 final LoggerRepository repository) {
279 // do nothing with this event
280 }
281
282
283 /**
284 * Stops all plugins associated with the repository being shutdown.
285 *
286 * @param repository the repository being shutdown.
287 */
288 public void shutdownEvent(final LoggerRepository repository) {
289 PluginRegistry.this.stopAllPlugins();
290 }
291 }
292 }