View Javadoc

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