View Javadoc

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   * Loads a single plugin from the descriptor provided, which can either be an InputStream
28   * or a resource on the classpath. The classes used by the plugin must already be available
29   * on the classpath because this plugin loader does <b>not</b> load any classes.
30   *
31   * @see PluginLoader
32   * @see ClassPathPluginLoader
33   */
34  public class SinglePluginLoader implements PluginLoader
35  {
36      protected Collection<Plugin> plugins;
37  
38      /**
39       * to load the Stream from the classpath.
40       */
41      private final String resource;
42  
43      /**
44       * to load the Stream directly.
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       * @deprecated use URL instead.
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       * @deprecated since 2.2 use the version that passes a URL instead. Not used by the plugins system.
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 }