1 package com.atlassian.plugin.loaders;
2
3 import com.atlassian.plugin.ModuleDescriptor;
4 import com.atlassian.plugin.ModuleDescriptorFactory;
5 import com.atlassian.plugin.Plugin;
6 import com.atlassian.plugin.PluginException;
7 import com.atlassian.plugin.PluginParseException;
8 import com.atlassian.plugin.impl.StaticPlugin;
9 import com.atlassian.plugin.impl.UnloadablePlugin;
10 import com.atlassian.plugin.impl.UnloadablePluginFactory;
11 import com.atlassian.plugin.parsers.DescriptorParser;
12 import com.atlassian.plugin.parsers.DescriptorParserFactory;
13 import com.atlassian.plugin.parsers.XmlDescriptorParserFactory;
14 import com.atlassian.plugin.util.ClassLoaderUtils;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.collect.ImmutableSet;
17 import org.dom4j.Element;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.net.URL;
24 import java.util.Collection;
25 import java.util.Collections;
26
27 import static com.atlassian.plugin.parsers.XmlDescriptorParserUtils.addModule;
28 import static com.atlassian.plugin.util.Assertions.notNull;
29
30
31
32
33
34
35
36
37
38 public class SinglePluginLoader implements PluginLoader {
39 protected Collection<Plugin> plugins;
40
41
42
43
44 private final String resource;
45
46
47
48
49 private final URL url;
50
51 private final DescriptorParserFactory descriptorParserFactory = new XmlDescriptorParserFactory();
52
53 private static final Logger log = LoggerFactory.getLogger(SinglePluginLoader.class);
54
55
56 public SinglePluginLoader(final String resource) {
57 this.resource = notNull("resource", resource);
58 url = null;
59 }
60
61 public SinglePluginLoader(final URL url) {
62 this.url = notNull("url", url);
63 resource = null;
64 }
65
66 public Iterable<Plugin> loadAllPlugins(final ModuleDescriptorFactory moduleDescriptorFactory) {
67 if (plugins == null) {
68 Plugin plugin;
69 try {
70 plugin = loadPlugin(moduleDescriptorFactory);
71 } catch (RuntimeException ex) {
72 String id = getIdentifier();
73 log.error("Error loading plugin or descriptor: " + id, ex);
74 plugin = new UnloadablePlugin(id + ": " + ex);
75 plugin.setKey(id);
76 }
77 plugins = Collections.singleton(plugin);
78 }
79 return ImmutableList.copyOf(plugins);
80 }
81
82 public boolean supportsRemoval() {
83 return false;
84 }
85
86 public boolean supportsAddition() {
87 return false;
88 }
89
90 public Iterable<Plugin> loadFoundPlugins(final ModuleDescriptorFactory moduleDescriptorFactory) {
91 throw new UnsupportedOperationException("This PluginLoader does not support addition.");
92 }
93
94 public void removePlugin(final Plugin plugin) throws PluginException {
95 throw new PluginException("This PluginLoader does not support removal.");
96 }
97
98 @Override
99 public boolean isDynamicPluginLoader() {
100 return false;
101 }
102
103 @Override
104 public ModuleDescriptor<?> createModule(final Plugin plugin, final Element module, final ModuleDescriptorFactory moduleDescriptorFactory) {
105 if (plugins.contains(plugin)) {
106 return addModule(moduleDescriptorFactory, plugin, module);
107 } else {
108 return null;
109 }
110 }
111
112 protected Plugin loadPlugin(final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException {
113 final InputStream source = getSource();
114 if (source == null) {
115 throw new PluginParseException("Invalid resource or inputstream specified to load plugins from.");
116 }
117
118 Plugin plugin;
119 try {
120 final DescriptorParser parser = descriptorParserFactory.getInstance(source, ImmutableSet.of());
121 plugin = parser.configurePlugin(moduleDescriptorFactory, getNewPlugin());
122 if (plugin.getPluginsVersion() == 2) {
123 UnloadablePlugin unloadablePlugin = UnloadablePluginFactory.createUnloadablePlugin(plugin);
124 final StringBuilder errorText = new StringBuilder("OSGi plugins cannot be deployed via the classpath, which is usually WEB-INF/lib.");
125 if (resource != null) {
126 errorText.append("\n Resource is: ").append(resource);
127 }
128 if (url != null) {
129 errorText.append("\n URL is: ").append(url);
130 }
131 unloadablePlugin.setErrorText(errorText.toString());
132 plugin = unloadablePlugin;
133 }
134 } catch (final PluginParseException e) {
135 throw new PluginParseException("Unable to load plugin resource: " + resource + " - " + e.getMessage(), e);
136 }
137
138 return plugin;
139 }
140
141 private String getIdentifier() {
142 if (resource != null) {
143 return resource;
144 }
145 if (url != null) {
146 return url.getPath();
147 }
148 return null;
149 }
150
151 protected StaticPlugin getNewPlugin() {
152 return new StaticPlugin();
153 }
154
155 protected InputStream getSource() {
156 if (resource != null) {
157 return ClassLoaderUtils.getResourceAsStream(resource, this.getClass());
158 }
159
160 if (url != null) {
161 try {
162 return url.openConnection().getInputStream();
163 } catch (IOException e) {
164 throw new PluginParseException(e);
165 }
166 }
167
168 throw new IllegalStateException("No defined method for getting an input stream.");
169 }
170 }