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