View Javadoc

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