View Javadoc
1   package com.atlassian.plugin.factories;
2   
3   import com.atlassian.plugin.Application;
4   import com.atlassian.plugin.ModuleDescriptor;
5   import com.atlassian.plugin.ModuleDescriptorFactory;
6   import com.atlassian.plugin.Plugin;
7   import com.atlassian.plugin.PluginArtifact;
8   import com.atlassian.plugin.PluginException;
9   import com.atlassian.plugin.PluginParseException;
10  import com.atlassian.plugin.impl.XmlDynamicPlugin;
11  import com.atlassian.plugin.parsers.DescriptorParser;
12  import com.atlassian.plugin.parsers.XmlDescriptorParserFactory;
13  import com.google.common.base.Predicate;
14  import com.google.common.base.Predicates;
15  import com.google.common.collect.Sets;
16  import org.apache.commons.io.IOUtils;
17  import org.dom4j.DocumentException;
18  import org.dom4j.Element;
19  import org.slf4j.Logger;
20  import org.slf4j.LoggerFactory;
21  
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.util.Set;
26  
27  import static com.google.common.base.Preconditions.checkNotNull;
28  
29  /**
30   * Deploys plugins that consist of an XML descriptor file.
31   *
32   * @since 2.1.0
33   */
34  public final class XmlDynamicPluginFactory extends AbstractPluginFactory {
35      private static final Logger log = LoggerFactory.getLogger(XmlDynamicPluginFactory.class);
36  
37      /**
38       * @param application The application key to use to choose modules
39       * @since 3.0
40       */
41      public XmlDynamicPluginFactory(final Application application) {
42          this(Sets.newHashSet(application));
43      }
44  
45      /**
46       * @param applications The application key to use to choose modules
47       * @since 3.0
48       */
49      public XmlDynamicPluginFactory(final Set<Application> applications) {
50          super(new XmlDescriptorParserFactory(), applications);
51      }
52  
53      @Override
54      protected InputStream getDescriptorInputStream(PluginArtifact pluginArtifact) {
55          return pluginArtifact.getInputStream();
56      }
57  
58      @Override
59      protected Predicate<Integer> isValidPluginsVersion() {
60          return Predicates.alwaysTrue();
61      }
62  
63      @Override
64      public String canCreate(PluginArtifact pluginArtifact) throws PluginParseException {
65          try {
66              return super.canCreate(pluginArtifact);
67          } catch (PluginParseException e) {
68              if (e.getCause() instanceof DocumentException) {
69                  log.debug("There was an error parsing the plugin descriptor for '{}'", pluginArtifact);
70                  log.debug("This is most probably because we parsed a jar, and the plugin is not an XML dynamic plugin. See the exception below for confirmation:", e);
71                  return null;
72              }
73              throw e;
74          }
75      }
76  
77      /**
78       * Deploys the plugin artifact
79       *
80       * @param pluginArtifact          the plugin artifact to deploy
81       * @param moduleDescriptorFactory The factory for plugin modules
82       * @return The instantiated and populated plugin
83       * @throws PluginParseException If the descriptor cannot be parsed
84       * @since 2.2.0
85       */
86      public Plugin create(final PluginArtifact pluginArtifact, final ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException {
87          checkNotNull(pluginArtifact, "The plugin artifact must not be null");
88          checkNotNull(moduleDescriptorFactory, "The module descriptor factory must not be null");
89  
90          InputStream pluginDescriptor = null;
91          try {
92              pluginDescriptor = new FileInputStream(pluginArtifact.toFile());
93              // The plugin we get back may not be the same (in the case of an UnloadablePlugin), so add what gets returned, rather than the original
94              final DescriptorParser parser = descriptorParserFactory.getInstance(pluginDescriptor, applications);
95              return parser.configurePlugin(moduleDescriptorFactory, new XmlDynamicPlugin(pluginArtifact));
96          } catch (final RuntimeException e) {
97              throw new PluginParseException(e);
98          } catch (final IOException e) {
99              throw new PluginParseException(e);
100         } finally {
101             IOUtils.closeQuietly(pluginDescriptor);
102         }
103     }
104 
105     @Override
106     public ModuleDescriptor<?> createModule(final Plugin plugin, final Element module, final ModuleDescriptorFactory moduleDescriptorFactory) {
107         if (plugin instanceof XmlDynamicPlugin) {
108             // It is possible to implement this, however this plugin type is not widely used and has no test coverage.
109             // If a use case emerges, we can revisit.
110             throw new PluginException("cannot create modules for an XmlDynamicPlugin");
111         }
112         return null;
113     }
114 }