/atlassian-plugins-core/src/main/java/com/atlassian/plugin/loaders/SinglePluginLoader.java

https://bitbucket.org/purewind/atlassian-plugins · Java · 192 lines · 144 code · 28 blank · 20 comment · 22 complexity · 7c96163864c441a0cf530043f09f83a5 MD5 · raw file

  1. package com.atlassian.plugin.loaders;
  2. import com.atlassian.plugin.Application;
  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. 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. import static com.atlassian.plugin.parsers.XmlDescriptorParserUtils.addModule;
  27. import static com.atlassian.plugin.util.Assertions.notNull;
  28. /**
  29. * Loads a single plugin from the descriptor provided, which can either be an InputStream
  30. * or a resource on the classpath. The classes used by the plugin must already be available
  31. * on the classpath because this plugin loader does <b>not</b> load any classes.
  32. *
  33. * @see PluginLoader
  34. * @see ClassPathPluginLoader
  35. */
  36. public class SinglePluginLoader implements PluginLoader {
  37. protected Collection<Plugin> plugins;
  38. /**
  39. * to load the Stream from the classpath.
  40. */
  41. private final String resource;
  42. /**
  43. * to load the Stream directly.
  44. */
  45. private final URL url;
  46. private final DescriptorParserFactory descriptorParserFactory = new XmlDescriptorParserFactory();
  47. private static final Logger log = LoggerFactory.getLogger(SinglePluginLoader.class);
  48. /**
  49. * @deprecated use URL instead.
  50. */
  51. private final AtomicReference<InputStream> inputStreamRef;
  52. public SinglePluginLoader(final String resource) {
  53. this.resource = notNull("resource", resource);
  54. url = null;
  55. inputStreamRef = new AtomicReference<InputStream>(null);
  56. }
  57. public SinglePluginLoader(final URL url) {
  58. this.url = notNull("url", url);
  59. resource = null;
  60. inputStreamRef = new AtomicReference<InputStream>(null);
  61. }
  62. /**
  63. * @deprecated since 2.2 use the version that passes a URL instead. Not used by the plugins system.
  64. */
  65. public SinglePluginLoader(final InputStream is) {
  66. inputStreamRef = new AtomicReference<InputStream>(notNull("inputStream", is));
  67. resource = null;
  68. url = null;
  69. }
  70. public Iterable<Plugin> loadAllPlugins(final ModuleDescriptorFactory moduleDescriptorFactory) {
  71. if (plugins == null) {
  72. Plugin plugin;
  73. try {
  74. plugin = loadPlugin(moduleDescriptorFactory);
  75. } catch (RuntimeException ex) {
  76. String id = getIdentifier();
  77. log.error("Error loading plugin or descriptor: " + id, ex);
  78. plugin = new UnloadablePlugin(id + ": " + ex);
  79. plugin.setKey(id);
  80. }
  81. plugins = Collections.singleton(plugin);
  82. }
  83. return ImmutableList.copyOf(plugins);
  84. }
  85. public boolean supportsRemoval() {
  86. return false;
  87. }
  88. public boolean supportsAddition() {
  89. return false;
  90. }
  91. public Iterable<Plugin> loadFoundPlugins(final ModuleDescriptorFactory moduleDescriptorFactory) {
  92. throw new UnsupportedOperationException("This PluginLoader does not support addition.");
  93. }
  94. public void removePlugin(final Plugin plugin) throws PluginException {
  95. throw new PluginException("This PluginLoader does not support removal.");
  96. }
  97. @Override
  98. public boolean isDynamicPluginLoader() {
  99. return false;
  100. }
  101. @Override
  102. public ModuleDescriptor<?> createModule(final Plugin plugin, final Element module, final ModuleDescriptorFactory moduleDescriptorFactory) {
  103. if (plugins.contains(plugin)) {
  104. return addModule(moduleDescriptorFactory, plugin, module);
  105. } else {
  106. return null;
  107. }
  108. }
  109. protected Plugin loadPlugin(final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException {
  110. final InputStream source = getSource();
  111. if (source == null) {
  112. throw new PluginParseException("Invalid resource or inputstream specified to load plugins from.");
  113. }
  114. Plugin plugin;
  115. try {
  116. final DescriptorParser parser = descriptorParserFactory.getInstance(source, ImmutableSet.<Application>of());
  117. plugin = parser.configurePlugin(moduleDescriptorFactory, getNewPlugin());
  118. if (plugin.getPluginsVersion() == 2) {
  119. UnloadablePlugin unloadablePlugin = UnloadablePluginFactory.createUnloadablePlugin(plugin);
  120. final StringBuilder errorText = new StringBuilder("OSGi plugins cannot be deployed via the classpath, which is usually WEB-INF/lib.");
  121. if (resource != null) {
  122. errorText.append("\n Resource is: ").append(resource);
  123. }
  124. if (url != null) {
  125. errorText.append("\n URL is: ").append(url);
  126. }
  127. unloadablePlugin.setErrorText(errorText.toString());
  128. plugin = unloadablePlugin;
  129. }
  130. } catch (final PluginParseException e) {
  131. throw new PluginParseException("Unable to load plugin resource: " + resource + " - " + e.getMessage(), e);
  132. }
  133. return plugin;
  134. }
  135. private String getIdentifier() {
  136. if (resource != null) {
  137. return resource;
  138. }
  139. if (url != null) {
  140. return url.getPath();
  141. }
  142. return inputStreamRef.toString();
  143. }
  144. protected StaticPlugin getNewPlugin() {
  145. return new StaticPlugin();
  146. }
  147. protected InputStream getSource() {
  148. if (resource != null) {
  149. return ClassLoaderUtils.getResourceAsStream(resource, this.getClass());
  150. }
  151. if (url != null) {
  152. try {
  153. return url.openConnection().getInputStream();
  154. } catch (IOException e) {
  155. throw new PluginParseException(e);
  156. }
  157. }
  158. final InputStream inputStream = inputStreamRef.getAndSet(null);
  159. if (inputStream != null) {
  160. return inputStream;
  161. }
  162. throw new IllegalStateException("No defined method for getting an input stream.");
  163. }
  164. }