View Javadoc

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