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