1 package com.atlassian.plugin.classloader;
2
3 import com.atlassian.plugin.MockPlugin;
4 import com.atlassian.plugin.MockPluginAccessor;
5 import com.atlassian.plugin.Plugin;
6 import com.atlassian.plugin.PluginAccessor;
7 import com.mockobjects.dynamic.C;
8 import com.mockobjects.dynamic.Mock;
9 import junit.framework.TestCase;
10
11 import java.net.MalformedURLException;
12 import java.net.URL;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.LinkedList;
16
17
18
19
20 public class TestPluginsClassLoader extends TestCase {
21 private static final String TEST_RESOURCE = "log4j.properties";
22
23 private PluginsClassLoader pluginsClassLoader;
24 private Mock mockPluginAccessor;
25 private Mock mockPlugin;
26 private static final String PLUGIN_KEY = "aPluginKey";
27 private static final String TEST_CLASS = "java.lang.String";
28
29 protected void setUp() throws Exception {
30 mockPluginAccessor = new Mock(PluginAccessor.class);
31 pluginsClassLoader = new PluginsClassLoader((PluginAccessor) mockPluginAccessor.proxy());
32
33 mockPlugin = new Mock(Plugin.class);
34 }
35
36 protected void tearDown() throws Exception {
37 mockPluginAccessor.verify();
38 mockPlugin.verify();
39
40 mockPluginAccessor = null;
41 pluginsClassLoader = null;
42 }
43
44 public void testFindResourceWhenIndexed() {
45 final StubClassLoader stubClassLoader = new StubClassLoader();
46 loadPluginResource(stubClassLoader);
47 assertTrue(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
48 stubClassLoader.clear();
49
50 mockPlugin.expectAndReturn("getKey", PLUGIN_KEY);
51 mockPluginAccessor.matchAndReturn("isPluginEnabled", C.args(C.eq(PLUGIN_KEY)), Boolean.TRUE);
52 mockPlugin.expectAndReturn("getClassLoader", stubClassLoader);
53 pluginsClassLoader.findResource(TEST_RESOURCE);
54
55 assertTrue(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
56 }
57
58 public void testFindResourceWhenNotIndexed() {
59 final StubClassLoader stubClassLoader = new StubClassLoader();
60 loadPluginResource(stubClassLoader);
61
62 assertTrue(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
63 }
64
65 public void testFindResourceWhenIndexedAndPluginDisabled() {
66 final StubClassLoader stubClassLoader = new StubClassLoader();
67 loadPluginResource(stubClassLoader);
68 assertTrue(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
69 stubClassLoader.clear();
70
71 mockPluginAccessor.expectAndReturn("getEnabledPlugins", Collections.emptyList());
72 mockPlugin.expectAndReturn("getKey", PLUGIN_KEY);
73 mockPluginAccessor.matchAndReturn("isPluginEnabled", C.args(C.eq(PLUGIN_KEY)), Boolean.FALSE);
74 pluginsClassLoader.findResource(TEST_RESOURCE);
75
76 assertFalse(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
77 }
78
79 public void testFindClassWhenIndexed() throws Exception {
80 final StubClassLoader stubClassLoader = new StubClassLoader();
81 loadPluginClass(stubClassLoader);
82 assertTrue(stubClassLoader.getFindClassNames().contains(TEST_CLASS));
83 stubClassLoader.clear();
84
85 mockPlugin.expectAndReturn("getKey", PLUGIN_KEY);
86 mockPluginAccessor.matchAndReturn("isPluginEnabled", C.args(C.eq(PLUGIN_KEY)), Boolean.TRUE);
87 mockPlugin.expectAndReturn("getClassLoader", stubClassLoader);
88 pluginsClassLoader.findClass(TEST_CLASS);
89
90 assertTrue(stubClassLoader.getFindClassNames().contains(TEST_CLASS));
91 }
92
93 public void testFindClassWhenNotIndexed() throws Exception {
94 final StubClassLoader stubClassLoader = new StubClassLoader();
95 loadPluginClass(stubClassLoader);
96
97 assertTrue(stubClassLoader.getFindClassNames().contains(TEST_CLASS));
98 }
99
100 public void testFindClassWhenIndexedAndPluginDisabled() throws Exception {
101 final StubClassLoader stubClassLoader = new StubClassLoader();
102 loadPluginClass(stubClassLoader);
103 assertTrue(stubClassLoader.getFindClassNames().contains(TEST_CLASS));
104 stubClassLoader.clear();
105
106 mockPluginAccessor.expectAndReturn("getEnabledPlugins", Collections.emptyList());
107 mockPlugin.expectAndReturn("getKey", PLUGIN_KEY);
108 mockPluginAccessor.matchAndReturn("isPluginEnabled", C.args(C.eq(PLUGIN_KEY)), Boolean.FALSE);
109 try {
110 pluginsClassLoader.findClass(TEST_CLASS);
111 fail("Plugin is disabled so its ClassLoader should throw ClassNotFoundException");
112 } catch (ClassNotFoundException e) {
113
114 }
115 }
116
117 public void testGetPluginForClass() throws Exception {
118 final MockPluginAccessor mockPluginAccessor = new MockPluginAccessor();
119 PluginsClassLoader pluginsClassLoader = new PluginsClassLoader(mockPluginAccessor);
120
121 MockClassLoader mockClassLoaderA = new MockClassLoader();
122 mockClassLoaderA.register("com.acme.Ant", String.class);
123 mockClassLoaderA.register("com.acme.Clash", String.class);
124 MockPlugin pluginA = new MockPlugin("A", mockClassLoaderA);
125 mockPluginAccessor.addPlugin(pluginA);
126
127 MockClassLoader mockClassLoaderB = new MockClassLoader();
128 mockClassLoaderB.register("com.acme.Bat", String.class);
129 mockClassLoaderB.register("com.acme.Clash", String.class);
130 MockPlugin pluginB = new MockPlugin("B", mockClassLoaderB);
131 mockPluginAccessor.addPlugin(pluginB);
132
133
134 assertEquals(null, pluginsClassLoader.getPluginForClass("com.acme.Ant"));
135 assertEquals(null, pluginsClassLoader.getPluginForClass("com.acme.Bat"));
136 assertEquals(null, pluginsClassLoader.getPluginForClass("com.acme.Clash"));
137 assertEquals(null, pluginsClassLoader.getPluginForClass("java.lang.String"));
138
139
140 pluginB.enable();
141 pluginsClassLoader.notifyPluginOrModuleEnabled();
142 assertEquals(null, pluginsClassLoader.getPluginForClass("com.acme.Ant"));
143 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Bat"));
144 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Clash"));
145 assertEquals(null, pluginsClassLoader.getPluginForClass("java.lang.String"));
146
147
148 pluginA.enable();
149 pluginsClassLoader.notifyPluginOrModuleEnabled();
150 assertEquals(pluginA, pluginsClassLoader.getPluginForClass("com.acme.Ant"));
151 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Bat"));
152 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Clash"));
153 assertEquals(null, pluginsClassLoader.getPluginForClass("java.lang.String"));
154
155
156 pluginsClassLoader.notifyUninstallPlugin(pluginB);
157 assertEquals(pluginA, pluginsClassLoader.getPluginForClass("com.acme.Ant"));
158 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Bat"));
159 assertEquals(pluginA, pluginsClassLoader.getPluginForClass("com.acme.Clash"));
160 assertEquals(null, pluginsClassLoader.getPluginForClass("java.lang.String"));
161 }
162
163 private void loadPluginResource(ClassLoader stubClassLoader) {
164 mockPluginAccessor.expectAndReturn("getEnabledPlugins", Collections.singleton(mockPlugin.proxy()));
165 mockPlugin.expectAndReturn("getClassLoader", stubClassLoader);
166 pluginsClassLoader.findResource(TEST_RESOURCE);
167 }
168
169 private void loadPluginClass(ClassLoader stubClassLoader) throws ClassNotFoundException {
170 mockPluginAccessor.expectAndReturn("getEnabledPlugins", Collections.singleton(mockPlugin.proxy()));
171 mockPlugin.expectAndReturn("getClassLoader", stubClassLoader);
172 pluginsClassLoader.findClass(TEST_CLASS);
173 }
174
175 private static final class StubClassLoader extends AbstractClassLoader {
176 private final Collection<String> findResourceNames = new LinkedList<String>();
177
178 public Collection getFindClassNames() {
179 return findClassNames;
180 }
181
182 private final Collection<String> findClassNames = new LinkedList<String>();
183
184 public StubClassLoader() {
185 super(null);
186 }
187
188 protected URL findResource(String name) {
189 findResourceNames.add(name);
190 try {
191 return new URL("file://" + name);
192 } catch (MalformedURLException e) {
193
194 return null;
195 }
196 }
197
198
199
200
201
202 public Class loadClass(String name) throws ClassNotFoundException {
203 return findClass(name);
204 }
205
206 protected Class findClass(String className) throws ClassNotFoundException {
207 findClassNames.add(className);
208 return String.class;
209 }
210
211 public Collection getFindResourceNames() {
212 return findResourceNames;
213 }
214
215 public void clear() {
216 findResourceNames.clear();
217 findClassNames.clear();
218 }
219 }
220 }