View Javadoc

1   package com.atlassian.plugin.loaders;
2   
3   import com.atlassian.plugin.AutowireCapablePlugin;
4   import com.atlassian.plugin.Plugin;
5   import com.atlassian.plugin.PluginArtifact;
6   import com.atlassian.plugin.PluginArtifactBackedPlugin;
7   import com.atlassian.plugin.event.PluginEventManager;
8   import com.atlassian.plugin.factories.PluginFactory;
9   import com.atlassian.plugin.impl.AbstractDelegatingPlugin;
10  import com.atlassian.plugin.loaders.classloading.Scanner;
11  import com.atlassian.plugin.module.ContainerAccessor;
12  import com.atlassian.plugin.module.ContainerManagedPlugin;
13  import com.atlassian.plugin.util.FileUtils;
14  
15  import java.io.File;
16  import java.io.IOException;
17  import java.net.URL;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  /**
22   * Plugin loader that can find plugins via a single URL, and treats all plugins loaded from
23   * the directory as bundled plugins, meaning they can can be upgraded, but not deleted.
24   * <p>
25   * Depending on the URL:
26   * <ul>
27   *     <li>If it is a file:// url and represents a directory, all the files in that directory are scanned.</li>
28   *     <li>if it is a file:// url and represents a file with a <code>.list</code> suffix, each line in that files
29   *     is read as a path to a plugin jar.</li>
30   *     <li>Otherwise it assumes the URL is a zip and unzips plugins from it into a local directory,
31   *     and ensures that directory only contains plugins from that zip file.  It also</li>
32   * </ul>
33   *
34   */
35  public class BundledPluginLoader extends ScanningPluginLoader
36  {
37      public BundledPluginLoader(final URL zipUrl, final File pluginPath, final List<PluginFactory> pluginFactories, final PluginEventManager eventManager)
38      {
39          super(buildScanner(zipUrl, pluginPath), pluginFactories, eventManager);
40      }
41  
42      @Override
43      protected Plugin postProcess(final Plugin plugin)
44      {
45          if (plugin instanceof ContainerManagedPlugin)
46          {
47              return new BundledPluginContainerManagedPluginDelegate((ContainerManagedPlugin) plugin);
48          }
49          else if (plugin instanceof PluginArtifactBackedPlugin)
50          {
51              return new BundledPluginArtifactBackedPluginDelegate((PluginArtifactBackedPlugin)plugin);
52          }
53          return new BundledPluginDelegate(plugin);
54      }
55  
56      private static Scanner buildScanner(final URL url, final File pluginPath)
57      {
58          if (url == null)
59          {
60              throw new IllegalArgumentException("Bundled plugins url cannot be null");
61          }
62  
63          Scanner scanner = null;
64  
65          final File file = FileUtils.toFile(url);
66  
67          if (file != null)
68          {
69              if (file.isDirectory())
70              {
71                  // URL points directly to a directory of jars
72                  scanner = new DirectoryScanner(file);
73              }
74              else if (file.isFile() && file.getName().endsWith(".list"))
75              {
76                  // URL points to a file containg a list of jars
77                  final List<File> files = readListFile(file);
78                  scanner = new FileListScanner(files);
79              }
80          }
81  
82          if (scanner == null) {
83              // default: assume it is a zip
84              FileUtils.conditionallyExtractZipFile(url, pluginPath);
85              scanner = new DirectoryScanner(pluginPath);
86          }
87  
88          return scanner;
89      }
90  
91      private static List<File> readListFile(final File file)
92      {
93          try
94          {
95              final List<String> fnames = (List<String>) org.apache.commons.io.FileUtils.readLines(file);
96              final List<File> files = new ArrayList<File>();
97              for (String fname : fnames)
98              {
99                  files.add(new File(fname));
100             }
101             return files;
102         }
103         catch (IOException e)
104         {
105             throw new IllegalStateException("Unable to read list from " + file, e);
106         }
107     }
108 
109 
110     /**
111      * Delegate that overrides methods to enforce bundled plugin behavior
112      *
113      * @since 2.2.0
114      */
115     private static class BundledPluginDelegate extends AbstractDelegatingPlugin
116     {
117 
118         public BundledPluginDelegate(Plugin delegate)
119         {
120             super(delegate);
121         }
122 
123         @Override
124         public boolean isBundledPlugin()
125         {
126             return true;
127         }
128 
129         @Override
130         public boolean isDeleteable()
131         {
132             return false;
133         }
134     }
135 
136     /**
137      * Delegate that overrides methods to enforce bundled plugin behavior for {@link PluginArtifactBackedPlugin} implementors
138      * @since 2.9.3
139      */
140     private static class BundledPluginArtifactBackedPluginDelegate extends BundledPluginDelegate implements PluginArtifactBackedPlugin
141     {
142         private final PluginArtifactBackedPlugin delegate;
143 
144         private BundledPluginArtifactBackedPluginDelegate(final PluginArtifactBackedPlugin delegate)
145         {
146             super(delegate);
147             this.delegate = delegate;
148         }
149 
150         public PluginArtifact getPluginArtifact()
151         {
152             return delegate.getPluginArtifact();
153         }
154     }
155 
156     private static class BundledPluginContainerManagedPluginDelegate extends BundledPluginArtifactBackedPluginDelegate implements ContainerManagedPlugin,
157             AutowireCapablePlugin
158     {
159         private final ContainerManagedPlugin delegate;
160 
161         private BundledPluginContainerManagedPluginDelegate(ContainerManagedPlugin delegate)
162         {
163             super(delegate);
164             this.delegate = delegate;
165         }
166 
167         @Override
168         public ContainerAccessor getContainerAccessor()
169         {
170             return delegate.getContainerAccessor();
171         }
172 
173         @Override
174         public <T> T autowire(Class<T> clazz)
175         {
176             if (delegate instanceof AutowireCapablePlugin)
177             {
178                 return ((AutowireCapablePlugin)delegate).autowire(clazz);
179             }
180             else
181             {
182                 return delegate.getContainerAccessor().createBean(clazz);
183             }
184         }
185 
186         @Override
187         public <T> T autowire(Class<T> clazz, AutowireStrategy autowireStrategy)
188         {
189             if (delegate instanceof AutowireCapablePlugin)
190             {
191                 return ((AutowireCapablePlugin)delegate).autowire(clazz, autowireStrategy);
192             }
193             else
194             {
195                 return delegate.getContainerAccessor().createBean(clazz);
196             }
197         }
198 
199         @Override
200         public void autowire(Object instance)
201         {
202             if (delegate instanceof AutowireCapablePlugin)
203             {
204                 ((AutowireCapablePlugin)delegate).autowire(instance);
205             }
206             else
207             {
208                 delegate.getContainerAccessor().injectBean(instance);
209             }
210         }
211 
212         @Override
213         public void autowire(Object instance, AutowireStrategy autowireStrategy)
214         {
215             if (delegate instanceof AutowireCapablePlugin)
216             {
217                 ((AutowireCapablePlugin)delegate).autowire(instance, autowireStrategy);
218             }
219             else
220             {
221                 delegate.getContainerAccessor().injectBean(instance);
222             }
223         }
224     }
225 }