View Javadoc

1   package com.atlassian.plugin.refimpl;
2   
3   import com.atlassian.plugin.DefaultModuleDescriptorFactory;
4   import com.atlassian.plugin.ModuleDescriptorFactory;
5   import com.atlassian.plugin.PluginAccessor;
6   import com.atlassian.plugin.PluginController;
7   import com.atlassian.plugin.PluginParseException;
8   import com.atlassian.plugin.event.PluginEventManager;
9   import com.atlassian.plugin.hostcontainer.HostContainer;
10  import com.atlassian.plugin.hostcontainer.SimpleConstructorHostContainer;
11  import com.atlassian.plugin.main.AtlassianPlugins;
12  import com.atlassian.plugin.main.PluginsConfiguration;
13  import com.atlassian.plugin.main.PluginsConfigurationBuilder;
14  import com.atlassian.plugin.osgi.container.OsgiContainerManager;
15  import com.atlassian.plugin.osgi.container.impl.DefaultPackageScannerConfiguration;
16  import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
17  import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
18  import com.atlassian.plugin.refimpl.servlet.SimpleServletContextFactory;
19  import com.atlassian.plugin.refimpl.webresource.SimpleWebResourceIntegration;
20  import com.atlassian.plugin.servlet.ContentTypeResolver;
21  import com.atlassian.plugin.servlet.DefaultServletModuleManager;
22  import com.atlassian.plugin.servlet.DownloadStrategy;
23  import com.atlassian.plugin.servlet.PluginResourceDownload;
24  import com.atlassian.plugin.servlet.ServletModuleManager;
25  import com.atlassian.plugin.servlet.descriptors.ServletContextListenerModuleDescriptor;
26  import com.atlassian.plugin.servlet.descriptors.ServletContextParamModuleDescriptor;
27  import com.atlassian.plugin.servlet.descriptors.ServletFilterModuleDescriptor;
28  import com.atlassian.plugin.servlet.descriptors.ServletModuleDescriptor;
29  import com.atlassian.plugin.util.Assertions;
30  import com.atlassian.plugin.web.descriptors.DefaultWebItemModuleDescriptor;
31  import com.atlassian.plugin.webresource.PluginResourceLocator;
32  import com.atlassian.plugin.webresource.PluginResourceLocatorImpl;
33  import com.atlassian.plugin.webresource.WebResourceIntegration;
34  import com.atlassian.plugin.webresource.WebResourceManager;
35  import com.atlassian.plugin.webresource.WebResourceManagerImpl;
36  import com.atlassian.plugin.webresource.WebResourceModuleDescriptor;
37  import org.apache.commons.lang.StringUtils;
38  import org.apache.commons.io.IOUtils;
39  
40  import javax.servlet.ServletContext;
41  import java.io.File;
42  import java.io.InputStream;
43  import java.io.IOException;
44  import java.util.*;
45  
46  /**
47   * A simple class that behaves like Spring's ContainerManager class.
48   */
49  public class ContainerManager
50  {
51      /**
52       * the name of the bundled plugins zip file to use
53       */
54      private static final String BUNDLED_PLUGINS_ZIP = "/atlassian-bundled-plugins.zip";
55  
56      private final ServletModuleManager servletModuleManager;
57      private final SimpleWebResourceIntegration webResourceIntegration;
58      private final WebResourceManager webResourceManager;
59      private final OsgiContainerManager osgiContainerManager;
60      private final PluginAccessor pluginAccessor;
61      private final HostComponentProvider hostComponentProvider;
62      private final DefaultModuleDescriptorFactory moduleDescriptorFactory;
63      private final Map<Class<?>, Object> publicContainer;
64      private final AtlassianPlugins plugins;
65  
66      private final HostContainer hostContainer;
67      private static ContainerManager instance;
68      private final List<DownloadStrategy> downloadStrategies;
69  
70      public ContainerManager(final ServletContext servletContext)
71      {
72          instance = this;
73          webResourceIntegration = new SimpleWebResourceIntegration(servletContext);
74  
75          // Delegating host container since the real one requires the created object map, which won't be available until later
76          final HostContainer delegatingHostContainer = new HostContainer()
77          {
78              public <T> T create(final Class<T> moduleClass) throws IllegalArgumentException
79              {
80                  return hostContainer.create(moduleClass);
81              }
82          };
83  
84          moduleDescriptorFactory = new DefaultModuleDescriptorFactory(delegatingHostContainer);
85  
86          moduleDescriptorFactory.addModuleDescriptor("servlet", ServletModuleDescriptor.class);
87          moduleDescriptorFactory.addModuleDescriptor("servlet-filter", ServletFilterModuleDescriptor.class);
88          moduleDescriptorFactory.addModuleDescriptor("servlet-context-param", ServletContextParamModuleDescriptor.class);
89          moduleDescriptorFactory.addModuleDescriptor("servlet-context-listener", ServletContextListenerModuleDescriptor.class);
90          moduleDescriptorFactory.addModuleDescriptor("web-resource", WebResourceModuleDescriptor.class);
91  
92          final DefaultPackageScannerConfiguration scannerConfig = new DefaultPackageScannerConfiguration(determineVersion());
93          final List<String> packageIncludes = new ArrayList<String>(scannerConfig.getPackageIncludes());
94          packageIncludes.add("org.bouncycastle*");
95          packageIncludes.add("org.dom4j*");
96  
97          scannerConfig.setPackageIncludes(packageIncludes);
98          hostComponentProvider = new SimpleHostComponentProvider();
99  
100         File osgiCache;
101         if (System.getProperty("osgi.cache") != null)
102         {
103             osgiCache = makeSureDirectoryExists(System.getProperty("osgi.cache"));
104         }
105         else
106         {
107             osgiCache = makeSureDirectoryExists(servletContext, "/WEB-INF/osgi-cache");
108         }
109 
110         final PluginsConfiguration config = new PluginsConfigurationBuilder()
111                 .useLegacyDynamicPluginDeployer(true)
112                 .bundledPluginUrl(this.getClass().getResource(BUNDLED_PLUGINS_ZIP))
113                 .bundledPluginCacheDirectory(makeSureDirectoryExists(servletContext, "/WEB-INF/bundled-plugins"))
114                 .pluginDirectory(makeSureDirectoryExists(servletContext, "/WEB-INF/plugins"))
115                 .moduleDescriptorFactory(moduleDescriptorFactory)
116                 .packageScannerConfiguration(scannerConfig)
117                 .hostComponentProvider(hostComponentProvider)
118                 .osgiPersistentCache(osgiCache)
119                 .build();
120         plugins = new AtlassianPlugins(config);
121 
122         final PluginEventManager pluginEventManager = plugins.getPluginEventManager();
123         osgiContainerManager = plugins.getOsgiContainerManager();
124 
125         servletModuleManager = new DefaultServletModuleManager(servletContext, pluginEventManager);
126         pluginAccessor = plugins.getPluginAccessor();
127 
128         PluginResourceLocator pluginResourceLocator = new PluginResourceLocatorImpl(pluginAccessor, new SimpleServletContextFactory(servletContext));
129         PluginResourceDownload pluginDownloadStrategy = new PluginResourceDownload(pluginResourceLocator, new SimpleContentTypeResolver(), "UTF-8");
130 
131         webResourceManager = new WebResourceManagerImpl(pluginResourceLocator, webResourceIntegration);
132 
133         publicContainer = new HashMap<Class<?>, Object>();
134         publicContainer.put(PluginController.class, plugins.getPluginController());
135         publicContainer.put(PluginAccessor.class, pluginAccessor);
136         publicContainer.put(ServletModuleManager.class, servletModuleManager);
137         publicContainer.put(WebResourceManager.class, webResourceManager);
138         publicContainer.put(Map.class, publicContainer);
139 
140         hostContainer = new SimpleConstructorHostContainer(publicContainer);
141 
142         try
143         {
144             plugins.start();
145         }
146         catch (final PluginParseException e)
147         {
148             throw new RuntimeException(e);
149         }
150 
151         downloadStrategies = new ArrayList<DownloadStrategy>();
152         downloadStrategies.add(pluginDownloadStrategy);
153     }
154 
155     private String determineVersion()
156     {
157         InputStream in = null;
158         Properties props = new Properties();
159         try
160         {
161             in = getClass().getClassLoader().getResourceAsStream("META-INF/maven/com.atlassian.plugins/atlassian-plugins-core/pom.properties");
162             if (in != null)
163             {
164                 props.load(in);
165                 return props.getProperty("version");
166             }
167         } catch (IOException e) {
168             e.printStackTrace();
169             return null;
170         }
171         finally
172         {
173             IOUtils.closeQuietly(in);
174         }
175         return null;
176     }
177 
178     private File makeSureDirectoryExists(ServletContext servletContext, String relativePath)
179     {
180         return makeSureDirectoryExists(servletContext.getRealPath(relativePath));
181     }
182 
183     private File makeSureDirectoryExists(String path)
184     {
185         File dir = new File(path);
186         if (!dir.exists() && !dir.mkdirs())
187         {
188             throw new RuntimeException("Could not create directory <" + dir + ">");
189         }
190         return dir;
191     }
192 
193     public static synchronized void setInstance(final ContainerManager mgr)
194     {
195         instance = mgr;
196     }
197 
198     public static synchronized ContainerManager getInstance()
199     {
200         return instance;
201     }
202 
203     public ServletModuleManager getServletModuleManager()
204     {
205         return servletModuleManager;
206     }
207 
208     public OsgiContainerManager getOsgiContainerManager()
209     {
210         return osgiContainerManager;
211     }
212 
213     public PluginAccessor getPluginAccessor()
214     {
215         return pluginAccessor;
216     }
217 
218     public HostComponentProvider getHostComponentProvider()
219     {
220         return hostComponentProvider;
221     }
222 
223     public ModuleDescriptorFactory getModuleDescriptorFactory()
224     {
225         return moduleDescriptorFactory;
226     }
227 
228     public List<DownloadStrategy> getDownloadStrategies()
229     {
230         return downloadStrategies;
231     }
232 
233     public WebResourceManager getWebResourceManager()
234     {
235         return webResourceManager;
236     }
237 
238     public WebResourceIntegration getWebResourceIntegration()
239     {
240         return webResourceIntegration;
241     }
242 
243     void shutdown()
244     {
245         plugins.stop();
246     }
247 
248     /**
249      * A simple content type resolver that can identify css and js resources.
250      */
251     private class SimpleContentTypeResolver implements ContentTypeResolver
252     {
253         private final Map<String, String> mimeTypes;
254 
255         SimpleContentTypeResolver()
256         {
257             final Map<String, String> types = new HashMap<String, String>();
258             types.put("js", "application/x-javascript");
259             types.put("css", "text/css");
260             mimeTypes = Collections.unmodifiableMap(types);
261         }
262 
263         public String getContentType(final String requestUrl)
264         {
265             final String extension = requestUrl.substring(requestUrl.lastIndexOf('.'));
266             return mimeTypes.get(extension);
267         }
268     }
269 
270     private class SimpleHostComponentProvider implements HostComponentProvider
271     {
272         public void provide(final ComponentRegistrar componentRegistrar)
273         {
274             Assertions.notNull("publicContainer", publicContainer);
275             for (final Map.Entry<Class<?>, Object> entry : publicContainer.entrySet())
276             {
277                 final String name = StringUtils.uncapitalize(entry.getKey().getSimpleName());
278                 componentRegistrar.register(entry.getKey()).forInstance(entry.getValue()).withName(name);
279             }
280 
281         }
282     }
283 }