1 package com.atlassian.plugin.loaders;
2
3 import com.atlassian.plugin.Application;
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.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.net.URL;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.concurrent.atomic.AtomicReference;
26
27 import static com.atlassian.plugin.util.Assertions.notNull;
28
29
30
31
32
33
34
35
36
37 public class SinglePluginLoader implements PluginLoader
38 {
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
57
58 private final AtomicReference<InputStream> inputStreamRef;
59
60
61 public SinglePluginLoader(final String resource)
62 {
63 this.resource = notNull("resource", resource);
64 url = null;
65 inputStreamRef = new AtomicReference<InputStream>(null);
66 }
67
68 public SinglePluginLoader(final URL url)
69 {
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 {
80 inputStreamRef = new AtomicReference<InputStream>(notNull("inputStream", is));
81 resource = null;
82 url = null;
83 }
84
85 public Iterable<Plugin> loadAllPlugins(final ModuleDescriptorFactory moduleDescriptorFactory)
86 {
87 if (plugins == null)
88 {
89 Plugin plugin;
90 try
91 {
92 plugin = loadPlugin(moduleDescriptorFactory);
93 }
94 catch (RuntimeException ex)
95 {
96 String id = getIdentifier();
97 log.error("Error loading plugin or descriptor: " + id, ex);
98 plugin = new UnloadablePlugin(id + ": " + ex);
99 plugin.setKey(id);
100 }
101 plugins = Collections.singleton(plugin);
102 }
103 return ImmutableList.copyOf(plugins);
104 }
105
106 public boolean supportsRemoval()
107 {
108 return false;
109 }
110
111 public boolean supportsAddition()
112 {
113 return false;
114 }
115
116 public Iterable<Plugin> loadFoundPlugins(final ModuleDescriptorFactory moduleDescriptorFactory)
117 {
118 throw new UnsupportedOperationException("This PluginLoader does not support addition.");
119 }
120
121 public void removePlugin(final Plugin plugin) throws PluginException
122 {
123 throw new PluginException("This PluginLoader does not support removal.");
124 }
125
126 @Override
127 public boolean isDynamicPluginLoader()
128 {
129 return false;
130 }
131
132 protected Plugin loadPlugin(final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
133 {
134 final InputStream source = getSource();
135 if (source == null)
136 {
137 throw new PluginParseException("Invalid resource or inputstream specified to load plugins from.");
138 }
139
140 Plugin plugin;
141 try
142 {
143 final DescriptorParser parser = descriptorParserFactory.getInstance(source, ImmutableSet.<Application>of());
144 plugin = parser.configurePlugin(moduleDescriptorFactory, getNewPlugin());
145 if (plugin.getPluginsVersion() == 2)
146 {
147 UnloadablePlugin unloadablePlugin = UnloadablePluginFactory.createUnloadablePlugin(plugin);
148 final StringBuilder errorText = new StringBuilder("OSGi plugins cannot be deployed via the classpath, which is usually WEB-INF/lib.");
149 if (resource != null) {
150 errorText.append("\n Resource is: ").append(resource);
151 }
152 if (url != null) {
153 errorText.append("\n URL is: ").append(url);
154 }
155 unloadablePlugin.setErrorText(errorText.toString());
156 plugin = unloadablePlugin;
157 }
158 }
159 catch (final PluginParseException e)
160 {
161 throw new PluginParseException("Unable to load plugin resource: " + resource + " - " + e.getMessage(), e);
162 }
163
164 return plugin;
165 }
166
167 private String getIdentifier()
168 {
169 if (resource != null) {
170 return resource;
171 }
172 if (url != null) {
173 return url.getPath();
174 }
175 return inputStreamRef.toString();
176 }
177
178 protected StaticPlugin getNewPlugin()
179 {
180 return new StaticPlugin();
181 }
182
183 protected InputStream getSource()
184 {
185 if (resource != null)
186 {
187 return ClassLoaderUtils.getResourceAsStream(resource, this.getClass());
188 }
189
190 if (url != null)
191 {
192 try
193 {
194 return url.openConnection().getInputStream();
195 }
196 catch (IOException e)
197 {
198 throw new PluginParseException(e);
199 }
200 }
201
202 final InputStream inputStream = inputStreamRef.getAndSet(null);
203 if (inputStream != null)
204 {
205 return inputStream;
206 }
207 throw new IllegalStateException("No defined method for getting an input stream.");
208 }
209 }