1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs2.impl;
18
19 import static org.apache.commons.vfs2.VfsTestUtils.getTestDirectoryFile;
20
21 import java.io.File;
22 import java.io.PrintWriter;
23 import java.net.URL;
24 import java.net.URLConnection;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Queue;
31 import java.util.concurrent.ArrayBlockingQueue;
32 import java.util.concurrent.BlockingQueue;
33 import java.util.concurrent.RejectedExecutionHandler;
34 import java.util.concurrent.ThreadFactory;
35 import java.util.concurrent.ThreadPoolExecutor;
36 import java.util.concurrent.TimeUnit;
37
38 import org.apache.commons.io.output.StringBuilderWriter;
39 import org.apache.commons.vfs2.AbstractProviderTestCase;
40 import org.apache.commons.vfs2.Capability;
41 import org.apache.commons.vfs2.FileObject;
42 import org.apache.commons.vfs2.FileSystemException;
43 import org.apache.commons.vfs2.FileSystemManager;
44 import org.apache.commons.vfs2.FileType;
45 import org.junit.Test;
46
47
48
49
50 public class VfsClassLoaderTests extends AbstractProviderTestCase {
51
52 private class LoadClass implements Runnable {
53 private final VFSClassLoader loader;
54 public LoadClass(final VFSClassLoader loader) {
55 this.loader = loader;
56 }
57
58 @Override
59 public void run() {
60 try {
61 final Class<?> testClass = loader.findClass("code.ClassToLoad");
62 final Package pack = testClass.getPackage();
63 assertEquals("code", pack.getName());
64 verifyPackage(pack, false);
65
66 final Object testObject = testClass.getConstructor().newInstance();
67 assertEquals("**PRIVATE**", testObject.toString());
68 } catch (final ReflectiveOperationException e) {
69 throw new IllegalStateException(e);
70 }
71 }
72 }
73
74
75
76
77 public static class MockClassloader extends ClassLoader {
78 MockClassloader() {
79 super(null);
80 }
81
82 @Override
83 protected Class<?> findClass(final String name) throws ClassNotFoundException {
84 fail("Not intended to be used for class loading.");
85 return null;
86 }
87
88
89
90
91 @Override
92 public Enumeration<URL> getResources(final String name) {
93 return Collections.enumeration(Collections.emptyList());
94 }
95 }
96
97
98
99
100 private VFSClassLoader createClassLoader() throws FileSystemException {
101 return new VFSClassLoader(getBaseFolder(), getManager());
102 }
103
104
105
106
107 @Override
108 protected Capability[] getRequiredCapabilities() {
109 return new Capability[] { Capability.READ_CONTENT, Capability.URI };
110 }
111
112
113
114
115
116
117
118
119 @Test
120 public void testGetResourcesJARs() throws Exception {
121 final FileSystemManager manager = getManager();
122 try {
123
124 manager.toFileObject(new File("."));
125 } catch (final FileSystemException e) {
126 System.out.println("VfsClassLoaderTests no local file provider, skipping.");
127 return;
128 }
129
130
131
132 final File baseDir = getTestDirectoryFile();
133 final FileObject nestedJar = manager.resolveFile(baseDir, "nested.jar");
134 final FileObject testJar = manager.resolveFile(baseDir, "test.jar");
135
136
137 if (!manager.canCreateFileSystem(nestedJar)) {
138 System.out.println("VfsClassLoaderTests no layered .jar provider, skipping.");
139 return;
140 }
141
142
143 assertSame("nested.jar is required for testing", nestedJar.getType(), FileType.FILE);
144 assertSame("test.jar is required for testing", testJar.getType(), FileType.FILE);
145
146
147
148
149 final ClassLoader mockClassloader = new MockClassloader();
150 final FileObject[] search = { nestedJar, testJar };
151 final VFSClassLoader loader = new VFSClassLoader(search, getManager(), mockClassloader);
152
153 final Enumeration<URL> urls = loader.getResources("META-INF/MANIFEST.MF");
154 final URL url1 = urls.nextElement();
155 final URL url2 = urls.nextElement();
156
157 assertTrue("First resource must refer to nested.jar but was " + url1,
158 url1.toString().endsWith("nested.jar!/META-INF/MANIFEST.MF"));
159 assertTrue("Second resource must refer to test.jar but was " + url2,
160 url2.toString().endsWith("test.jar!/META-INF/MANIFEST.MF"));
161 }
162
163
164
165
166
167
168
169 @Test
170 public void testGetResourcesNoLayerLocal() throws Exception {
171 final FileSystemManager manager = getManager();
172 try {
173
174 manager.toFileObject(new File("."));
175 } catch (final FileSystemException e) {
176 System.out.println("VfsClassLoaderTests no local file provider, skipping.");
177 return;
178 }
179 final File baseDir = getTestDirectoryFile();
180
181
182 final FileObject dir = manager.resolveFile(baseDir, "read-tests/dir1/subdir4.jar");
183 assertSame("subdir4.jar/ is required for testing " + dir, dir.getType(), FileType.FOLDER);
184 assertFalse(manager.canCreateFileSystem(dir));
185
186
187 final FileObject[] search = { dir };
188 final ClassLoader mockClassloader = new MockClassloader();
189 final VFSClassLoader loader = new VFSClassLoader(search, getManager(), mockClassloader);
190
191
192 final Enumeration<URL> urls = loader.getResources("file1.txt");
193 final URL url1 = urls.nextElement();
194 assertFalse("Only one hit expected", urls.hasMoreElements());
195 assertTrue("not pointing to resource " + url1, url1.toString().endsWith("subdir4.jar/file1.txt"));
196 }
197
198
199
200
201 @Test
202 public void testLoadClass() throws Exception {
203 final VFSClassLoader loader = createClassLoader();
204
205 final Class<?> testClass = loader.loadClass("code.ClassToLoad");
206 final Package pack = testClass.getPackage();
207 assertEquals("code", pack.getName());
208 verifyPackage(pack, false);
209
210 final Object testObject = testClass.getConstructor().newInstance();
211 assertEquals("**PRIVATE**", testObject.toString());
212 }
213
214
215
216
217 @Test
218 public void testLoadResource() throws Exception {
219 final VFSClassLoader loader = createClassLoader();
220
221 final URL resource = loader.getResource("read-tests/file1.txt");
222
223 assertNotNull(resource);
224 final URLConnection urlCon = resource.openConnection();
225 assertSameURLContent(FILE1_CONTENT, urlCon);
226 }
227
228
229
230
231 @Test
232 public void testSealing() throws Exception {
233 final VFSClassLoader loader = createClassLoader();
234 final Class<?> testClass = loader.loadClass("code.sealed.AnotherClass");
235 final Package pack = testClass.getPackage();
236 assertEquals("code.sealed", pack.getName());
237 verifyPackage(pack, true);
238 }
239
240 @Test
241 public void testThreadSafety() throws Exception {
242 final int THREADS = 40;
243 final BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(THREADS * 2);
244 final List<Throwable> exceptions = new ArrayList<>();
245 final Thread.UncaughtExceptionHandler handler = (t, e) -> {
246 synchronized (exceptions) {
247 exceptions.add(e);
248 }
249 };
250 final ThreadFactory factory = r -> {
251 final Thread thread = new Thread(r, "VfsClassLoaderTests.testThreadSafety");
252 thread.setUncaughtExceptionHandler(handler);
253 return thread;
254 };
255 final Queue<Runnable> rejections = new LinkedList<>();
256 final RejectedExecutionHandler rejectionHandler = (r, executor) -> {
257 synchronized (rejections) {
258 rejections.add(r);
259 }
260 };
261 final ThreadPoolExecutor executor = new ThreadPoolExecutor(THREADS, THREADS, 0, TimeUnit.SECONDS, workQueue, factory, rejectionHandler);
262 executor.prestartAllCoreThreads();
263 for (int i = 0; i < THREADS; i++) {
264 final VFSClassLoader loader = createClassLoader();
265 workQueue.put(new VfsClassLoaderTests.LoadClass(loader));
266 }
267 while (!workQueue.isEmpty()) {
268 Thread.sleep(10);
269 }
270 while (!rejections.isEmpty() && executor.getActiveCount() > 0) {
271 final List<Runnable> rejected = new ArrayList<>();
272 synchronized(rejections) {
273 rejected.addAll(rejections);
274 rejections.clear();
275 }
276 workQueue.addAll(rejected);
277 }
278 executor.shutdown();
279 executor.awaitTermination(30, TimeUnit.SECONDS);
280 assertEquals(THREADS, executor.getCompletedTaskCount());
281 if (!exceptions.isEmpty()) {
282 final StringBuilder exceptionMsg = new StringBuilder();
283 final StringBuilderWriter writer = new StringBuilderWriter(exceptionMsg);
284 final PrintWriter pWriter = new PrintWriter(writer);
285 for (final Throwable t : exceptions) {
286 pWriter.write(t.getMessage());
287 pWriter.write('\n');
288 t.printStackTrace(pWriter);
289 pWriter.write('\n');
290 }
291 pWriter.flush();
292 assertTrue(exceptions.size() + " threads failed: " + exceptionMsg, exceptions.isEmpty());
293 }
294 }
295
296
297
298
299 private void verifyPackage(final Package pack, final boolean sealed) {
300 if (getBaseFolder().getFileSystem().hasCapability(Capability.MANIFEST_ATTRIBUTES)) {
301 assertEquals("ImplTitle", pack.getImplementationTitle());
302 assertEquals("ImplVendor", pack.getImplementationVendor());
303 assertEquals("1.1", pack.getImplementationVersion());
304 assertEquals("SpecTitle", pack.getSpecificationTitle());
305 assertEquals("SpecVendor", pack.getSpecificationVendor());
306 assertEquals("1.0", pack.getSpecificationVersion());
307 assertEquals(sealed, pack.isSealed());
308 } else {
309 assertNull(pack.getImplementationTitle());
310 assertNull(pack.getImplementationVendor());
311 assertNull(pack.getImplementationVersion());
312 assertNull(pack.getSpecificationTitle());
313 assertNull(pack.getSpecificationVendor());
314 assertNull(pack.getSpecificationVersion());
315 assertFalse(pack.isSealed());
316 }
317 }
318
319 }