View Javadoc

1   package com.atlassian.plugin.factories;
2   
3   import com.atlassian.plugin.*;
4   import com.atlassian.plugin.classloader.PluginClassLoader;
5   import com.atlassian.plugin.impl.DefaultDynamicPlugin;
6   import com.atlassian.plugin.impl.DynamicPlugin;
7   import com.atlassian.plugin.loaders.classloading.DeploymentUnit;
8   import com.atlassian.plugin.parsers.DescriptorParser;
9   import com.atlassian.plugin.parsers.DescriptorParserFactory;
10  import com.atlassian.plugin.parsers.XmlDescriptorParserFactory;
11  import org.apache.commons.io.IOUtils;
12  import org.apache.commons.lang.Validate;
13  
14  import java.io.File;
15  import java.io.IOException;
16  import java.io.InputStream;
17  import java.net.URL;
18  
19  /**
20   * Deploys version 1.0 plugins into the legacy custom classloader structure that gives each plugin its own classloader.
21   *
22   * @since 2.0.0
23   */
24  public class LegacyDynamicPluginFactory implements PluginFactory
25  {
26      private DescriptorParserFactory descriptorParserFactory;
27      private String pluginDescriptorFileName;
28      private final File tempDirectory;
29  
30      public LegacyDynamicPluginFactory(String pluginDescriptorFileName)
31      {
32          this(pluginDescriptorFileName,new File(System.getProperty("java.io.tmpdir")));
33      }
34  
35      public LegacyDynamicPluginFactory(String pluginDescriptorFileName, File tempDirectory)
36      {
37          this.tempDirectory = tempDirectory;
38          Validate.notEmpty(pluginDescriptorFileName, "Plugin descriptor name cannot be null or blank");
39          this.descriptorParserFactory = new XmlDescriptorParserFactory();
40          this.pluginDescriptorFileName = pluginDescriptorFileName;
41      }
42  
43      /**
44       * @deprecated Since 2.2.0, use {@link #create(PluginArtifact,ModuleDescriptorFactory)} instead
45       */
46      public Plugin create(DeploymentUnit deploymentUnit, ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
47      {
48          return create(new JarPluginArtifact(deploymentUnit.getPath()), moduleDescriptorFactory);
49      }
50  
51      /**
52       * Deploys the plugin artifact
53       * @param pluginArtifact the plugin artifact to deploy
54       * @param moduleDescriptorFactory The factory for plugin modules
55       * @return The instantiated and populated plugin
56       * @throws PluginParseException If the descriptor cannot be parsed
57       * @since 2.2.0
58       */
59      public Plugin create(PluginArtifact pluginArtifact, ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
60      {
61          Validate.notNull(pluginArtifact, "The deployment unit must not be null");
62          Validate.notNull(moduleDescriptorFactory, "The module descriptor factory must not be null");
63  
64          File file = pluginArtifact.toFile();
65          Plugin plugin = null;
66          InputStream pluginDescriptor = null;
67          PluginClassLoader loader = null;
68          try
69          {
70              pluginDescriptor = pluginArtifact.getResourceAsStream(pluginDescriptorFileName);
71              if (pluginDescriptor == null)
72                  throw new PluginParseException("No descriptor found in classloader for : " + file);
73  
74              // 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
75              DescriptorParser parser = descriptorParserFactory.getInstance(pluginDescriptor);
76              loader = new PluginClassLoader(file, Thread.currentThread().getContextClassLoader(), tempDirectory);
77              plugin = parser.configurePlugin(moduleDescriptorFactory, createPlugin(pluginArtifact, loader));
78          }
79          // Under normal conditions, the deployer would be closed when the plugins are undeployed. However,
80          // these are not normal conditions, so we need to make sure that we close them explicitly.
81          catch (PluginParseException e)
82          {
83              if (loader != null) loader.close();
84              throw e;
85          }
86          catch (RuntimeException e)
87          {
88              if (loader != null) loader.close();
89              throw new PluginParseException(e);
90          }
91          catch (Error e)
92          {
93              if (loader != null) loader.close();
94              throw e;
95          } finally
96          {
97              IOUtils.closeQuietly(pluginDescriptor);
98          }
99          return plugin;
100     }
101 
102     /**
103      * @deprecated Since 2.2.0, use {@link #createPlugin(PluginArtifact,PluginClassLoader)} instead
104      */
105     protected DynamicPlugin createPlugin(DeploymentUnit deploymentUnit, PluginClassLoader loader)
106     {
107         return createPlugin(new JarPluginArtifact(deploymentUnit.getPath()), loader);
108     }
109 
110     /**
111      * Creates the plugin.  Override to use a different Plugin class
112      * @param pluginArtifact The plugin artifact
113      * @param loader The plugin loader
114      * @return The plugin instance
115      * @since 2.2.0
116      */
117     protected DynamicPlugin createPlugin(PluginArtifact pluginArtifact, PluginClassLoader loader)
118     {
119         return new DefaultDynamicPlugin(pluginArtifact, loader);
120     }
121 
122     /**
123      * Determines if this deployer can handle this artifact by looking for the plugin descriptor
124      *
125      * @param pluginArtifact The artifact to test
126      * @return The plugin key, null if it cannot load the plugin
127      * @throws com.atlassian.plugin.PluginParseException If there are exceptions parsing the plugin configuration
128      */
129     public String canCreate(PluginArtifact pluginArtifact) throws PluginParseException
130     {
131         Validate.notNull(pluginArtifact, "The plugin artifact must not be null");
132         String pluginKey = null;
133         final InputStream descriptorStream = pluginArtifact.getResourceAsStream(pluginDescriptorFileName);
134         if (descriptorStream != null)
135         {
136             try
137             {
138                 final DescriptorParser descriptorParser = descriptorParserFactory.getInstance(descriptorStream);
139 
140                 // Only recognize version 1 plugins
141                 if (descriptorParser.getPluginsVersion() <= 1)
142                     pluginKey = descriptorParser.getKey();
143             } finally
144             {
145                 IOUtils.closeQuietly(descriptorStream);
146             }
147         }
148         return pluginKey;
149     }
150 }