View Javadoc

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