View Javadoc
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 }