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