View Javadoc
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   * Base for in-container unit tests
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         // dirty hack for running inside IDE, as the current directory is the project root, not the module
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(); // prevent export cache from being reused across tests
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 }