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