1 package it.com.atlassian.plugin.osgi;
2
3 import com.atlassian.plugin.osgi.AbstractWaitCondition;
4 import com.atlassian.plugin.osgi.PluginInContainerTestBase;
5 import com.atlassian.plugin.osgi.StaticHolder;
6 import com.atlassian.plugin.test.PluginJarBuilder;
7 import com.atlassian.plugin.util.WaitUntil;
8 import com.google.common.base.Function;
9 import com.google.common.collect.Lists;
10 import my.AcceptedClassLoadersRetriever;
11 import my.StrongClassCacheRetriever;
12 import org.hamcrest.FeatureMatcher;
13 import org.hamcrest.Matcher;
14 import org.junit.Test;
15 import org.osgi.framework.BundleReference;
16
17 import java.io.IOException;
18 import java.util.Arrays;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.concurrent.Callable;
22
23 import static java.util.concurrent.TimeUnit.MILLISECONDS;
24 import static org.hamcrest.CoreMatchers.equalTo;
25 import static org.hamcrest.CoreMatchers.hasItems;
26 import static org.hamcrest.CoreMatchers.not;
27 import static org.hamcrest.MatcherAssert.assertThat;
28 import static org.hamcrest.Matchers.empty;
29
30 public class TestMarkBundleClassesCacheableListener extends PluginInContainerTestBase {
31 @Test
32 public void testBundleClassesAreCacheableInSpring() throws Exception {
33 withSystemProperty("atlassian.enable.spring.strong.cache.bean.metadata", "true", new Callable<Void>() {
34 @Override
35 public Void call() throws Exception {
36 preparePluginWithClass(AcceptedClassLoadersRetriever.class);
37
38 initPluginManager();
39 final Set<ClassLoader> acceptedClassLoaders = StaticHolder.get();
40
41 assertThat(acceptedClassLoaders,
42 hasModuleClassLoadersWithKeys("test.plugin", "com.atlassian.plugin.osgi.bridge"));
43
44 pluginController.disablePlugin("test.plugin");
45 assertThatSoon(acceptedClassLoaders,
46 not(hasModuleClassLoadersWithKeys("test.plugin")));
47
48
49 pluginController.enablePlugins("test.plugin");
50 assertThatSoon(acceptedClassLoaders,
51 hasModuleClassLoadersWithKeys("test.plugin"));
52
53 pluginSystemLifecycle.shutdown();
54 assertThat(acceptedClassLoaders, empty());
55
56 return null;
57 }
58 });
59 }
60
61 @Test
62 public void testBundleClassesAreNotCacheableByDefaultInSpring() throws Exception {
63 preparePluginWithClass(AcceptedClassLoadersRetriever.class);
64
65 initPluginManager();
66 final Set<ClassLoader> acceptedClassLoaders = StaticHolder.get();
67
68 assertThat(acceptedClassLoaders, not(hasModuleClassLoadersWithKeys("test.plugin")));
69
70 pluginController.disablePlugin("test.plugin");
71 pluginController.enablePlugins("test.plugin");
72 assertThatSoon(acceptedClassLoaders, not(hasModuleClassLoadersWithKeys("test.plugin")));
73
74 pluginSystemLifecycle.shutdown();
75 assertThat(acceptedClassLoaders, empty());
76 }
77
78 @Test
79 public void testBundleClassesCacheIsFlushed() throws Exception {
80 withSystemProperty("atlassian.enable.spring.strong.cache.bean.metadata.flush", "true", new Callable<Void>() {
81 @Override
82 public Void call() throws Exception {
83 preparePluginWithClass(StrongClassCacheRetriever.class);
84
85 initPluginManager();
86
87 final Map<?, ?> classCache = StaticHolder.get();
88
89 assertThat(classCache.entrySet(), empty());
90
91 return null;
92 }
93 });
94 }
95
96 @Test
97 public void testBundleClassesCacheIsNotFlushedByDefault() throws Exception {
98 preparePluginWithClass(StrongClassCacheRetriever.class);
99
100 initPluginManager();
101
102 final Map<?, ?> classCache = StaticHolder.get();
103
104 assertThat(classCache.entrySet(), not(empty()));
105 }
106
107 private void preparePluginWithClass(Class clazz) throws IOException {
108 new PluginJarBuilder("testClassLoaderCachedChecker")
109 .addFormattedResource("atlassian-plugin.xml",
110 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
111 " <plugin-info>",
112 " <version>1.0</version>",
113 " </plugin-info>",
114 " <component key='obj' class='" + clazz.getName() + "'/>",
115 "</atlassian-plugin>")
116 .addClass(clazz)
117 .build(pluginsDir);
118 }
119
120 private Matcher<Iterable<ClassLoader>> hasModuleClassLoadersWithKeys(String... keys) {
121 Matcher<ClassLoader>[] matchers = Lists.transform(Arrays.asList(keys), new Function<String, Matcher<ClassLoader>>() {
122 @Override
123 public Matcher<ClassLoader> apply(String key) {
124 return classLoaderWithBundleName(key);
125 }
126 }).toArray(new Matcher[keys.length]);
127 return hasItems(matchers);
128 }
129
130 private Matcher<ClassLoader> classLoaderWithBundleName(final String bundleName) {
131 return new FeatureMatcher<ClassLoader, String>(equalTo(bundleName), "a class loader for bundle", "bundle of a class loader") {
132 @Override
133 protected String featureValueOf(ClassLoader actual) {
134 if (actual instanceof BundleReference) {
135 BundleReference moduleClassLoader = (BundleReference) actual;
136 return moduleClassLoader.getBundle().getSymbolicName();
137 }
138 return null;
139 }
140 };
141 }
142
143 private <T> T withSystemProperty(String key, String value, Callable<T> action) throws Exception {
144 String originalValue = System.setProperty(key, value);
145 try {
146 return action.call();
147 } finally {
148 if (originalValue != null) {
149 System.setProperty(key, originalValue);
150 } else {
151 System.clearProperty(key);
152 }
153 }
154 }
155
156 private static <T> void assertThatSoon(final T actual, final Matcher<? super T> matcher) {
157
158
159 WaitUntil.invoke(new AbstractWaitCondition() {
160 @Override
161 public boolean isFinished() {
162
163
164 synchronized (actual) {
165 return matcher.matches(actual);
166 }
167 }
168 }, 500, MILLISECONDS, 50);
169 assertThat(actual, matcher);
170 }
171 }