1 package com.atlassian.plugin.loaders;
2
3 import com.atlassian.plugin.*;
4 import com.atlassian.plugin.event.PluginEventListener;
5 import com.atlassian.plugin.event.PluginEventManager;
6 import com.atlassian.plugin.event.events.PluginFrameworkShutdownEvent;
7 import com.atlassian.plugin.factories.PluginFactory;
8 import com.atlassian.plugin.impl.UnloadablePlugin;
9 import com.atlassian.plugin.loaders.classloading.DeploymentUnit;
10 import com.atlassian.plugin.loaders.classloading.Scanner;
11
12 import org.apache.commons.lang.Validate;
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.TreeMap;
22
23
24
25
26
27
28
29 public class ScanningPluginLoader implements DynamicPluginLoader
30 {
31 private static Log log = LogFactory.getLog(DirectoryPluginLoader.class);
32 protected final com.atlassian.plugin.loaders.classloading.Scanner scanner;
33 protected final Map<DeploymentUnit, Plugin> plugins;
34 protected final List<PluginFactory> pluginFactories;
35 protected final PluginArtifactFactory pluginArtifactFactory;
36
37
38
39
40
41
42
43
44
45 public ScanningPluginLoader(final Scanner scanner, final List<PluginFactory> pluginFactories, final PluginEventManager pluginEventManager)
46 {
47 this(scanner, pluginFactories, new DefaultPluginArtifactFactory(), pluginEventManager);
48 }
49
50
51
52
53
54
55
56
57
58
59 public ScanningPluginLoader(final Scanner scanner, final List<PluginFactory> pluginFactories, final PluginArtifactFactory pluginArtifactFactory, final PluginEventManager pluginEventManager)
60 {
61 Validate.notNull(pluginFactories, "The list of plugin factories must be specified");
62 Validate.notNull(pluginEventManager, "The event manager must be specified");
63 Validate.notNull(scanner, "The scanner must be specified");
64
65 plugins = new TreeMap<DeploymentUnit, Plugin>();
66
67 this.pluginArtifactFactory = pluginArtifactFactory;
68 this.scanner = scanner;
69 this.pluginFactories = new ArrayList<PluginFactory>(pluginFactories);
70
71 pluginEventManager.register(this);
72 }
73
74 public Collection<Plugin> loadAllPlugins(final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
75 {
76 scanner.scan();
77
78 for (final DeploymentUnit deploymentUnit : scanner.getDeploymentUnits())
79 {
80 try
81 {
82 final Plugin plugin = deployPluginFromUnit(deploymentUnit, moduleDescriptorFactory);
83 plugins.put(deploymentUnit, plugin);
84 }
85 catch (final PluginParseException e)
86 {
87
88
89
90 log.error("Error loading descriptor for : " + deploymentUnit, e);
91 }
92 }
93
94 if (scanner.getDeploymentUnits().isEmpty())
95 {
96 log.info("No plugins found to be deployed");
97 }
98
99 return plugins.values();
100 }
101
102 protected Plugin deployPluginFromUnit(final DeploymentUnit deploymentUnit, final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
103 {
104 Plugin plugin = null;
105 String errorText = "No plugin factories found for plugin file " + deploymentUnit;
106
107 String pluginKey = null;
108 for (final PluginFactory factory : pluginFactories)
109 {
110 try
111 {
112 final PluginArtifact artifact = pluginArtifactFactory.create(deploymentUnit.getPath().toURI());
113 pluginKey = factory.canCreate(artifact);
114 if (pluginKey != null)
115 {
116 plugin = factory.create(artifact, moduleDescriptorFactory);
117 if (plugin != null)
118 {
119 break;
120 }
121 }
122 }
123 catch (final PluginParseException ex)
124 {
125 throw ex;
126 }
127 catch (final RuntimeException ex)
128 {
129 log.error("Unable to deploy plugin '" + pluginKey + "', file " + deploymentUnit, ex);
130 errorText = ex.getMessage();
131 }
132 }
133 if (plugin == null)
134 {
135 plugin = new UnloadablePlugin(errorText);
136 if (pluginKey != null)
137 {
138 plugin.setKey(pluginKey);
139 }
140 }
141 else
142 {
143 log.info("Plugin " + deploymentUnit + " created");
144 }
145
146 return plugin;
147 }
148
149 public boolean supportsRemoval()
150 {
151 return true;
152 }
153
154 public boolean supportsAddition()
155 {
156 return true;
157 }
158
159
160
161
162
163 public Collection<Plugin> addFoundPlugins(final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
164 {
165
166 final Collection<DeploymentUnit> updatedDeploymentUnits = scanner.scan();
167
168
169 final List<Plugin> foundPlugins = new ArrayList<Plugin>();
170 for (final DeploymentUnit deploymentUnit : updatedDeploymentUnits)
171 {
172 if (!plugins.containsKey(deploymentUnit))
173 {
174 final Plugin plugin = deployPluginFromUnit(deploymentUnit, moduleDescriptorFactory);
175 plugins.put(deploymentUnit, plugin);
176 foundPlugins.add(plugin);
177 }
178 }
179 if (foundPlugins.isEmpty())
180 {
181 log.info("No plugins found to be installed");
182 }
183
184 return foundPlugins;
185 }
186
187
188
189
190
191 public void removePlugin(final Plugin plugin) throws PluginException
192 {
193 if (plugin.getPluginState() == PluginState.ENABLED)
194 {
195 throw new PluginException("Cannot remove an enabled plugin");
196 }
197
198 if (!plugin.isUninstallable())
199 {
200 throw new PluginException("Cannot remove an uninstallable plugin: [" + plugin.getName() + "]");
201 }
202
203 final DeploymentUnit deploymentUnit = findMatchingDeploymentUnit(plugin);
204 plugin.close();
205
206 try
207 {
208
209
210
211 boolean found = false;
212 for (final DeploymentUnit unit : plugins.keySet())
213 {
214 if (unit.getPath().equals(deploymentUnit.getPath()) && !unit.equals(deploymentUnit))
215 {
216 found = true;
217 break;
218 }
219 }
220
221 if (!found)
222 {
223 scanner.remove(deploymentUnit);
224 }
225 }
226 catch (final SecurityException e)
227 {
228 throw new PluginException(e);
229 }
230
231 plugins.remove(deploymentUnit);
232 log.info("Removed plugin " + plugin.getKey());
233 }
234
235 private DeploymentUnit findMatchingDeploymentUnit(final Plugin plugin) throws PluginException
236 {
237 DeploymentUnit deploymentUnit = null;
238 for (final Map.Entry<DeploymentUnit, Plugin> entry : plugins.entrySet())
239 {
240
241
242
243 if (entry.getValue() == plugin)
244 {
245 deploymentUnit = entry.getKey();
246 break;
247 }
248 }
249
250 if (deploymentUnit == null)
251 {
252 throw new PluginException("This pluginLoader has no memory of deploying the plugin you are trying remove: [" + plugin.getName() + "]");
253 }
254 return deploymentUnit;
255 }
256
257
258
259
260
261 @PluginEventListener
262 public void onShutdown(final PluginFrameworkShutdownEvent event)
263 {
264 for (final Iterator<Plugin> it = plugins.values().iterator(); it.hasNext();)
265 {
266 final Plugin plugin = it.next();
267 plugin.close();
268 it.remove();
269 }
270
271 scanner.reset();
272 }
273
274
275
276
277 @Deprecated
278 public void shutDown()
279 {
280 onShutdown(null);
281 }
282
283
284
285
286
287
288
289
290 public String canLoad(final PluginArtifact pluginArtifact) throws PluginParseException
291 {
292 String pluginKey = null;
293 for (final PluginFactory factory : pluginFactories)
294 {
295 pluginKey = factory.canCreate(pluginArtifact);
296 if (pluginKey != null)
297 {
298 break;
299 }
300 }
301 return pluginKey;
302 }
303 }