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