1 package com.atlassian.plugin.osgi;
2
3 import com.atlassian.plugin.Application;
4 import com.atlassian.plugin.DefaultModuleDescriptorFactory;
5 import com.atlassian.plugin.ModuleDescriptorFactory;
6 import com.atlassian.plugin.PluginAccessor;
7 import com.atlassian.plugin.PluginController;
8 import com.atlassian.plugin.PluginRegistry;
9 import com.atlassian.plugin.SplitStartupPluginSystemLifecycle;
10 import com.atlassian.plugin.event.PluginEventManager;
11 import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
12 import com.atlassian.plugin.factories.LegacyDynamicPluginFactory;
13 import com.atlassian.plugin.factories.PluginFactory;
14 import com.atlassian.plugin.hostcontainer.SimpleConstructorHostContainer;
15 import com.atlassian.plugin.loaders.BundledPluginLoader;
16 import com.atlassian.plugin.loaders.DirectoryPluginLoader;
17 import com.atlassian.plugin.loaders.PluginLoader;
18 import com.atlassian.plugin.manager.DefaultPluginManager;
19 import com.atlassian.plugin.manager.EnabledModuleCachingPluginAccessor;
20 import com.atlassian.plugin.manager.PluginPersistentStateStore;
21 import com.atlassian.plugin.manager.PluginRegistryImpl;
22 import com.atlassian.plugin.manager.ProductPluginAccessor;
23 import com.atlassian.plugin.manager.store.MemoryPluginPersistentStateStore;
24 import com.atlassian.plugin.module.ClassPrefixModuleFactory;
25 import com.atlassian.plugin.module.ModuleFactory;
26 import com.atlassian.plugin.module.PrefixDelegatingModuleFactory;
27 import com.atlassian.plugin.module.PrefixModuleFactory;
28 import com.atlassian.plugin.osgi.container.OsgiPersistentCache;
29 import com.atlassian.plugin.osgi.container.PackageScannerConfiguration;
30 import com.atlassian.plugin.osgi.container.felix.FelixOsgiContainerManager;
31 import com.atlassian.plugin.osgi.container.impl.DefaultOsgiPersistentCache;
32 import com.atlassian.plugin.osgi.container.impl.DefaultPackageScannerConfiguration;
33 import com.atlassian.plugin.osgi.factory.OsgiBundleFactory;
34 import com.atlassian.plugin.osgi.factory.OsgiPluginFactory;
35 import com.atlassian.plugin.osgi.factory.RemotablePluginFactory;
36 import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
37 import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
38 import com.atlassian.plugin.osgi.hostcomponents.InstanceBuilder;
39 import com.atlassian.plugin.osgi.module.BeanPrefixModuleFactory;
40 import com.atlassian.plugin.repositories.FilePluginInstaller;
41 import com.atlassian.plugin.scope.AlwaysEnabledScopeManager;
42 import com.atlassian.plugin.scope.ScopeManager;
43 import com.atlassian.plugin.test.PluginTestUtils;
44 import com.google.common.collect.ImmutableList;
45 import com.google.common.collect.ImmutableSet;
46 import org.apache.commons.io.FileUtils;
47 import org.apache.commons.io.IOUtils;
48 import org.junit.After;
49 import org.junit.Before;
50 import org.junit.runner.RunWith;
51 import org.junit.runners.Parameterized;
52
53 import java.io.File;
54 import java.io.FileInputStream;
55 import java.io.FileOutputStream;
56 import java.io.IOException;
57 import java.io.InputStream;
58 import java.util.Arrays;
59 import java.util.Collection;
60 import java.util.Collections;
61 import java.util.HashMap;
62 import java.util.List;
63 import java.util.Map;
64 import java.util.zip.ZipEntry;
65 import java.util.zip.ZipOutputStream;
66
67
68
69
70 @RunWith(Parameterized.class)
71 public abstract class PluginInContainerTestBase {
72 protected FelixOsgiContainerManager osgiContainerManager;
73 protected File tmpDir;
74 protected File cacheDir;
75 protected File pluginsDir;
76 protected File frameworkBundlesDir;
77 protected ModuleDescriptorFactory moduleDescriptorFactory;
78 protected PluginController pluginController;
79 protected PluginAccessor pluginAccessor;
80 protected SplitStartupPluginSystemLifecycle pluginSystemLifecycle;
81 protected PluginEventManager pluginEventManager;
82 protected ModuleFactory moduleFactory;
83 protected SimpleConstructorHostContainer hostContainer;
84 protected PluginPersistentStateStore store;
85
86 private interface PluginManagerProvider {
87 class InitialisedPluginManager {
88 final PluginController pluginController;
89 final PluginAccessor pluginAccessor;
90 final SplitStartupPluginSystemLifecycle pluginSystemLifecycle;
91 final PluginPersistentStateStore store;
92
93 private InitialisedPluginManager(final PluginController pluginController,
94 final PluginAccessor pluginAccessor,
95 final SplitStartupPluginSystemLifecycle pluginSystemLifecycle,
96 PluginPersistentStateStore store) {
97 this.pluginController = pluginController;
98 this.pluginAccessor = pluginAccessor;
99 this.pluginSystemLifecycle = pluginSystemLifecycle;
100 this.store = store;
101 }
102 }
103
104 InitialisedPluginManager provide(final ModuleDescriptorFactory moduleDescriptorFactory,
105 final List<PluginLoader> loader,
106 final PluginEventManager pluginEventManager,
107 final File pluginsDir);
108 }
109
110 @Parameterized.Parameters(name = "{index}: {0}")
111 public static Collection<Object[]> data() {
112 return Arrays.asList(new Object[][]{
113 {"DefaultPluginManager", new PluginManagerProvider() {
114 @Override
115 public InitialisedPluginManager provide(final ModuleDescriptorFactory moduleDescriptorFactory,
116 final List<PluginLoader> loader,
117 final PluginEventManager pluginEventManager,
118 final File pluginsDir) {
119 final PluginPersistentStateStore store = new MemoryPluginPersistentStateStore();
120 DefaultPluginManager pluginManager = new DefaultPluginManager(store, loader, moduleDescriptorFactory, pluginEventManager);
121 pluginManager.setPluginInstaller(new FilePluginInstaller(pluginsDir));
122 return new InitialisedPluginManager(pluginManager, pluginManager, pluginManager, store);
123 }
124 }},
125 {"EnabledModuleCachingPluginAccessor", new PluginManagerProvider() {
126 @Override
127 public InitialisedPluginManager provide(final ModuleDescriptorFactory moduleDescriptorFactory,
128 final List<PluginLoader> loader,
129 final PluginEventManager pluginEventManager,
130 final File pluginsDir) {
131
132 final MemoryPluginPersistentStateStore store = new MemoryPluginPersistentStateStore();
133 DefaultPluginManager pluginManager = new DefaultPluginManager(store, loader, moduleDescriptorFactory, pluginEventManager);
134 pluginManager.setPluginInstaller(new FilePluginInstaller(pluginsDir));
135 return new InitialisedPluginManager(
136 pluginManager,
137 new EnabledModuleCachingPluginAccessor(pluginManager, pluginEventManager, pluginManager),
138 pluginManager,
139 store);
140 }
141 }},
142 {"ProductPluginAccessor", new PluginManagerProvider() {
143 @Override
144 public InitialisedPluginManager provide(final ModuleDescriptorFactory moduleDescriptorFactory,
145 final List<PluginLoader> loader,
146 final PluginEventManager pluginEventManager,
147 final File pluginsDir) {
148 PluginRegistry.ReadWrite pluginRegistry = new PluginRegistryImpl();
149 PluginPersistentStateStore store = new MemoryPluginPersistentStateStore();
150 ScopeManager scopeManager = new AlwaysEnabledScopeManager();
151
152 PluginAccessor pluginAccessor = new ProductPluginAccessor(pluginRegistry, store, moduleDescriptorFactory, pluginEventManager, scopeManager);
153
154 DefaultPluginManager pluginManager = DefaultPluginManager.newBuilder()
155 .withPluginRegistry(pluginRegistry)
156 .withStore(store)
157 .withPluginEventManager(pluginEventManager)
158 .withPluginLoaders(loader)
159 .withModuleDescriptorFactory(moduleDescriptorFactory)
160 .withPluginAccessor(pluginAccessor)
161 .build();
162
163 pluginManager.setPluginInstaller(new FilePluginInstaller(pluginsDir));
164
165 return new InitialisedPluginManager(pluginManager, pluginAccessor, pluginManager, store);
166 }
167 }},
168 });
169 }
170
171 @Parameterized.Parameter(value = 0)
172 public String testDescription;
173
174 @Parameterized.Parameter(value = 1)
175 public PluginManagerProvider pluginManagerProvider;
176
177 @Before
178 public void setUp() throws Exception {
179 tmpDir = PluginTestUtils.createTempDirectory(this.getClass().getName() + testDescription);
180 cacheDir = new File(tmpDir, "cache");
181 cacheDir.mkdir();
182 pluginsDir = new File(tmpDir, "plugins");
183 pluginsDir.mkdir();
184 this.pluginEventManager = new DefaultPluginEventManager();
185 moduleFactory = new PrefixDelegatingModuleFactory(ImmutableSet.<PrefixModuleFactory>of(
186 new ClassPrefixModuleFactory(hostContainer),
187 new BeanPrefixModuleFactory()));
188 hostContainer = createHostContainer(new HashMap<Class<?>, Object>());
189
190
191 if (new File("atlassian-plugins-osgi").exists()) {
192 frameworkBundlesDir = new File(new File("atlassian-plugins-osgi", "target"), "framework-bundles");
193 } else {
194 frameworkBundlesDir = new File("target", "framework-bundles");
195 }
196 if (!frameworkBundlesDir.exists()) {
197 throw new IllegalStateException(
198 "frameworkBundlesDir does not exist '" + frameworkBundlesDir.getAbsolutePath() + "', " +
199 "ensure that you have run a maven build up to process-resources");
200 }
201 }
202
203 protected SimpleConstructorHostContainer createHostContainer(Map<Class<?>, Object> originalContext) {
204 Map<Class<?>, Object> context = new HashMap<Class<?>, Object>(originalContext);
205 context.put(ModuleFactory.class, moduleFactory);
206 return new SimpleConstructorHostContainer(context);
207 }
208
209 @After
210 public void tearDown() throws Exception {
211 if (osgiContainerManager != null) {
212 osgiContainerManager.stop();
213 osgiContainerManager.clearExportCache();
214 }
215 FileUtils.deleteDirectory(tmpDir);
216 osgiContainerManager = null;
217 tmpDir = null;
218 pluginsDir = null;
219 moduleDescriptorFactory = null;
220 pluginEventManager = null;
221 moduleFactory = null;
222 hostContainer = null;
223 }
224
225 protected void initPluginManager() throws Exception {
226 initPluginManager(null, new DefaultModuleDescriptorFactory(hostContainer));
227 }
228
229 protected void initPluginManager(final HostComponentProvider hostComponentProvider) throws Exception {
230 initPluginManager(hostComponentProvider, new DefaultModuleDescriptorFactory(hostContainer));
231 }
232
233 protected void initPluginManager(final HostComponentProvider hostComponentProvider, final ModuleDescriptorFactory moduleDescriptorFactory, final String version)
234 throws Exception {
235 final PackageScannerConfiguration scannerConfig = buildScannerConfiguration(version);
236 HostComponentProvider requiredWrappingProvider = getWrappingHostComponentProvider(hostComponentProvider);
237 OsgiPersistentCache cache = new DefaultOsgiPersistentCache(cacheDir);
238 osgiContainerManager = new FelixOsgiContainerManager(frameworkBundlesDir, cache, scannerConfig, requiredWrappingProvider, pluginEventManager);
239
240 final LegacyDynamicPluginFactory legacyFactory = new LegacyDynamicPluginFactory(PluginAccessor.Descriptor.FILENAME, tmpDir);
241 final OsgiPluginFactory osgiPluginDeployer = new OsgiPluginFactory(PluginAccessor.Descriptor.FILENAME, Collections.<Application>emptySet(), cache, osgiContainerManager, pluginEventManager);
242 final OsgiBundleFactory osgiBundleFactory = new OsgiBundleFactory(osgiContainerManager);
243 final RemotablePluginFactory remotablePluginFactory = new RemotablePluginFactory(PluginAccessor.Descriptor.FILENAME, Collections.<Application>emptySet(), osgiContainerManager, pluginEventManager);
244
245 final DirectoryPluginLoader loader = new DirectoryPluginLoader(pluginsDir,
246 ImmutableList.<PluginFactory>of(legacyFactory, osgiPluginDeployer, osgiBundleFactory, remotablePluginFactory),
247 new DefaultPluginEventManager());
248
249 initPluginManager(moduleDescriptorFactory, loader);
250 }
251
252 protected void initPluginManager(final HostComponentProvider hostComponentProvider, final ModuleDescriptorFactory moduleDescriptorFactory)
253 throws Exception {
254 initPluginManager(hostComponentProvider, moduleDescriptorFactory, (String) null);
255 }
256
257 protected void initPluginManager(final ModuleDescriptorFactory moduleDescriptorFactory, final List<PluginLoader> loader)
258 throws Exception {
259 this.moduleDescriptorFactory = moduleDescriptorFactory;
260 PluginManagerProvider.InitialisedPluginManager initialisedPluginManager = pluginManagerProvider.provide(moduleDescriptorFactory, loader, pluginEventManager, pluginsDir);
261 pluginController = initialisedPluginManager.pluginController;
262 pluginAccessor = initialisedPluginManager.pluginAccessor;
263 pluginSystemLifecycle = initialisedPluginManager.pluginSystemLifecycle;
264 store = initialisedPluginManager.store;
265 pluginSystemLifecycle.init();
266 }
267
268 protected void initPluginManager(final ModuleDescriptorFactory moduleDescriptorFactory, PluginLoader loader)
269 throws Exception {
270 initPluginManager(moduleDescriptorFactory, Arrays.<PluginLoader>asList(loader));
271 }
272
273 protected void initBundlingPluginManager(final ModuleDescriptorFactory moduleDescriptorFactory, File... bundledPluginJars) throws Exception {
274 this.moduleDescriptorFactory = moduleDescriptorFactory;
275 final PackageScannerConfiguration scannerConfig = buildScannerConfiguration("1.0");
276 HostComponentProvider requiredWrappingProvider = getWrappingHostComponentProvider(null);
277 OsgiPersistentCache cache = new DefaultOsgiPersistentCache(cacheDir);
278 osgiContainerManager = new FelixOsgiContainerManager(frameworkBundlesDir, cache, scannerConfig, requiredWrappingProvider, pluginEventManager);
279
280 final OsgiPluginFactory osgiPluginDeployer = new OsgiPluginFactory(PluginAccessor.Descriptor.FILENAME, Collections.<Application>emptySet(), cache, osgiContainerManager, pluginEventManager);
281
282 final DirectoryPluginLoader loader = new DirectoryPluginLoader(pluginsDir, Arrays.<PluginFactory>asList(osgiPluginDeployer),
283 new DefaultPluginEventManager());
284
285 File zip = new File(bundledPluginJars[0].getParentFile(), "bundled-plugins.zip");
286 for (File bundledPluginJar : bundledPluginJars) {
287 ZipOutputStream stream = null;
288 InputStream in = null;
289 try {
290 stream = new ZipOutputStream(new FileOutputStream(zip));
291 in = new FileInputStream(bundledPluginJar);
292 stream.putNextEntry(new ZipEntry(bundledPluginJar.getName()));
293 IOUtils.copy(in, stream);
294 stream.closeEntry();
295 } catch (IOException ex) {
296 IOUtils.closeQuietly(in);
297 IOUtils.closeQuietly(stream);
298 }
299 }
300 File bundledDir = new File(bundledPluginJars[0].getParentFile(), "bundled-plugins");
301 final BundledPluginLoader bundledLoader = new BundledPluginLoader(zip.toURL(), bundledDir, Arrays.<PluginFactory>asList(osgiPluginDeployer),
302 new DefaultPluginEventManager());
303
304 initPluginManager(moduleDescriptorFactory, Arrays.<PluginLoader>asList(bundledLoader, loader));
305 }
306
307 private HostComponentProvider getWrappingHostComponentProvider(final HostComponentProvider hostComponentProvider) {
308 HostComponentProvider requiredWrappingProvider = new HostComponentProvider() {
309 public void provide(final ComponentRegistrar registrar) {
310
311 if (hostComponentProvider != null) {
312 hostComponentProvider.provide(new ComponentRegistrar() {
313 public InstanceBuilder register(Class<?>... mainInterfaces) {
314 if (!Arrays.asList(mainInterfaces).contains(PluginEventManager.class)) {
315 return registrar.register(mainInterfaces);
316 }
317 return null;
318 }
319 });
320 }
321 registrar.register(ModuleFactory.class).forInstance(moduleFactory);
322 registrar.register(PluginEventManager.class).forInstance(pluginEventManager);
323 registrar.register(PluginAccessor.class).forInstance(pluginAccessor);
324 }
325 };
326 return requiredWrappingProvider;
327 }
328
329 private PackageScannerConfiguration buildScannerConfiguration(String version) {
330 final PackageScannerConfiguration scannerConfig = new DefaultPackageScannerConfiguration(version);
331 scannerConfig.getPackageIncludes().add("com.atlassian.plugin*");
332 scannerConfig.getPackageIncludes().add("javax.servlet*");
333 scannerConfig.getPackageIncludes().add("com_cenqua_clover");
334 scannerConfig.getPackageExcludes().add("com.atlassian.plugin.osgi.bridge*");
335 scannerConfig.getPackageExcludes().add("com.atlassian.plugin.osgi.bridge.external");
336 scannerConfig.getPackageExcludes().add("com.atlassian.plugin.osgi.spring.external");
337 scannerConfig.getPackageVersions().put("org.apache.commons.logging", "1.1.3");
338 return scannerConfig;
339 }
340 }