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