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
48
49 public class ContainerManager
50 {
51
52
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
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
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 }