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