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