View Javadoc

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   * Loads a single plugin from the descriptor provided, which can either be an InputStream
31   * or a resource on the classpath. The classes used by the plugin must already be available
32   * on the classpath because this plugin loader does <b>not</b> load any classes.
33   *
34   * @see PluginLoader
35   * @see ClassPathPluginLoader
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      private static final Logger log = LoggerFactory.getLogger(SinglePluginLoader.class);
54  
55      /**
56       * @deprecated use URL instead.
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       * @deprecated since 2.2 use the version that passes a URL instead. Not used by the plugins system.
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 }