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