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