View Javadoc

1   package com.atlassian.plugin.loaders;
2   
3   import static com.atlassian.plugin.util.Assertions.notNull;
4   
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  
17  import java.io.IOException;
18  import java.io.InputStream;
19  import java.net.URL;
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.concurrent.atomic.AtomicReference;
23  
24  /**
25   * Loads a single plugin from the descriptor provided, which can either be an InputStream
26   * or a resource on the classpath. The classes used by the plugin must already be available
27   * on the classpath because this plugin loader does <b>not</b> load any classes.
28   * <p/>
29   * Because the code which is run by these plugins must already be in the classpath (and
30   * is therefore more trusted than an uploaded plugin), if the plugin is marked as a system
31   * plugin in the descriptor file, it will actually be marked as a system plugin at runtime.
32   *
33   * @see PluginLoader
34   * @see ClassPathPluginLoader
35   * @see DescriptorParser#isSystemPlugin()
36   */
37  public class SinglePluginLoader implements PluginLoader
38  {
39      protected Collection<Plugin> plugins;
40  
41      /**
42       * to load the Stream from the classpath.
43       */
44      private final String resource;
45  
46      /**
47       * to load the Stream directly.
48       */
49      private final URL url;
50  
51      private final DescriptorParserFactory descriptorParserFactory = new XmlDescriptorParserFactory();
52  
53      /**
54       * @deprecated use URL instead.
55       */
56      private final AtomicReference<InputStream> inputStreamRef;
57  
58  
59      public SinglePluginLoader(final String resource)
60      {
61          this.resource = notNull("resource", resource);
62          url = null;
63          inputStreamRef = new AtomicReference<InputStream>(null);
64      }
65  
66      public SinglePluginLoader(final URL url)
67      {
68          this.url = notNull("url", url);
69          resource = null;
70          inputStreamRef = new AtomicReference<InputStream>(null);
71      }
72  
73      /**
74       * @deprecated since 2.2 use the version that passes a URL instead. Not used by the plugins system.
75       */
76      public SinglePluginLoader(final InputStream is)
77      {
78          inputStreamRef = new AtomicReference<InputStream>(notNull("inputStream", is));
79          resource = null;
80          url = null;
81      }
82  
83      public Collection<Plugin> loadAllPlugins(final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
84      {
85          if (plugins == null)
86          {
87              plugins = Collections.singleton(loadPlugin(moduleDescriptorFactory));
88          }
89          return plugins;
90      }
91  
92      public boolean supportsRemoval()
93      {
94          return false;
95      }
96  
97      public boolean supportsAddition()
98      {
99          return false;
100     }
101 
102     public Collection<Plugin> addFoundPlugins(final ModuleDescriptorFactory moduleDescriptorFactory)
103     {
104         throw new UnsupportedOperationException("This PluginLoader does not support addition.");
105     }
106 
107     public void removePlugin(final Plugin plugin) throws PluginException
108     {
109         throw new PluginException("This PluginLoader does not support removal.");
110     }
111 
112     protected Plugin loadPlugin(final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
113     {
114         final InputStream source = getSource();
115         if (source == null)
116         {
117             throw new PluginParseException("Invalid resource or inputstream specified to load plugins from.");
118         }
119 
120         Plugin plugin;
121         try
122         {
123             final DescriptorParser parser = descriptorParserFactory.getInstance(source);
124             plugin = parser.configurePlugin(moduleDescriptorFactory, getNewPlugin());
125             if (plugin.getPluginsVersion() == 2)
126             {
127                 UnloadablePlugin unloadablePlugin = UnloadablePluginFactory.createUnloadablePlugin(plugin);
128                 final StringBuilder errorText = new StringBuilder("OSGi plugins cannot be deployed via the classpath, which is usually WEB-INF/lib.");
129                 if (resource != null) {
130                     errorText.append(" Resource is: " + resource);
131                 }
132                 if (url != null) {
133                     errorText.append(" URL is: " + url);
134                 }
135                 unloadablePlugin.setErrorText(errorText.toString());
136                 plugin = unloadablePlugin;
137             }
138             else if (parser.isSystemPlugin())
139             {
140                 plugin.setSystemPlugin(true);
141             }
142         }
143         catch (final PluginParseException e)
144         {
145             throw new PluginParseException("Unable to load plugin resource: " + resource + " - " + e.getMessage(), e);
146         }
147 
148         return plugin;
149     }
150 
151     protected StaticPlugin getNewPlugin()
152     {
153         return new StaticPlugin();
154     }
155 
156     protected InputStream getSource()
157     {
158         if (resource != null)
159         {
160             return ClassLoaderUtils.getResourceAsStream(resource, this.getClass());
161         }
162 
163         if (url != null)
164         {
165             try
166             {
167                 return url.openConnection().getInputStream();
168             }
169             catch (IOException e)
170             {
171                 throw new PluginParseException(e);
172             }
173         }
174 
175         final InputStream inputStream = inputStreamRef.getAndSet(null);
176         if (inputStream != null)
177         {
178             return inputStream;
179         }
180         throw new IllegalStateException("No defined method for getting an input stream.");
181     }
182 }