1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.jimfs; 18 19 import static java.nio.charset.StandardCharsets.UTF_8; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertTrue; 23 24 import com.google.common.base.MoreObjects; 25 import com.google.common.collect.ImmutableList; 26 import java.io.IOException; 27 import java.lang.reflect.Method; 28 import java.net.URLClassLoader; 29 import java.nio.file.FileSystem; 30 import java.nio.file.Files; 31 import java.nio.file.Path; 32 import java.nio.file.spi.FileSystemProvider; 33 import java.util.List; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 import org.junit.runners.JUnit4; 37 38 /** 39 * Tests behavior when user code loads Jimfs in a separate class loader from the system class loader 40 * (which is what {@link FileSystemProvider#installedProviders()} uses to load {@link 41 * FileSystemProvider}s as services from the classpath). 42 * 43 * @author Colin Decker 44 */ 45 @RunWith(JUnit4.class) 46 public class ClassLoaderTest { 47 48 @Test separateClassLoader()49 public void separateClassLoader() throws Exception { 50 ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); 51 ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); 52 53 ClassLoader loader = MoreObjects.firstNonNull(contextLoader, systemLoader); 54 55 if (loader instanceof URLClassLoader) { 56 // Anything we can do if it isn't a URLClassLoader? 57 URLClassLoader urlLoader = (URLClassLoader) loader; 58 59 ClassLoader separateLoader = 60 new URLClassLoader( 61 urlLoader.getURLs(), systemLoader.getParent()); // either null or the boostrap loader 62 63 Thread.currentThread().setContextClassLoader(separateLoader); 64 try { 65 Class<?> thisClass = separateLoader.loadClass(getClass().getName()); 66 Method createFileSystem = thisClass.getDeclaredMethod("createFileSystem"); 67 68 // First, the call to Jimfs.newFileSystem in createFileSystem needs to succeed 69 Object fs = createFileSystem.invoke(null); 70 71 // Next, some sanity checks: 72 73 // The file system is a JimfsFileSystem 74 assertEquals("com.google.common.jimfs.JimfsFileSystem", fs.getClass().getName()); 75 76 // But it is not seen as an instance of JimfsFileSystem here because it was loaded by a 77 // different ClassLoader 78 assertFalse(fs instanceof JimfsFileSystem); 79 80 // But it should be an instance of FileSystem regardless, which is the important thing. 81 assertTrue(fs instanceof FileSystem); 82 83 // And normal file operations should work on it despite its provenance from a different 84 // ClassLoader 85 writeAndRead((FileSystem) fs, "bar.txt", "blah blah"); 86 87 // And for the heck of it, test the contents of the file that was created in 88 // createFileSystem too 89 assertEquals( 90 "blah", Files.readAllLines(((FileSystem) fs).getPath("foo.txt"), UTF_8).get(0)); 91 } finally { 92 Thread.currentThread().setContextClassLoader(contextLoader); 93 } 94 } 95 } 96 97 /** 98 * This method is really just testing that {@code Jimfs.newFileSystem()} succeeds. Without special 99 * handling, when the system class loader loads our {@code FileSystemProvider} implementation as a 100 * service and this code (the user code) is loaded in a separate class loader, the system-loaded 101 * provider won't see the instance of {@code Configuration} we give it as being an instance of the 102 * {@code Configuration} it's expecting (they're completely separate classes) and creation of the 103 * file system will fail. 104 */ createFileSystem()105 public static FileSystem createFileSystem() throws IOException { 106 FileSystem fs = Jimfs.newFileSystem(Configuration.unix()); 107 108 // Just some random operations to verify that basic things work on the created file system. 109 writeAndRead(fs, "foo.txt", "blah"); 110 111 return fs; 112 } 113 writeAndRead(FileSystem fs, String path, String text)114 private static void writeAndRead(FileSystem fs, String path, String text) throws IOException { 115 Path p = fs.getPath(path); 116 Files.write(p, ImmutableList.of(text), UTF_8); 117 List<String> lines = Files.readAllLines(p, UTF_8); 118 assertEquals(text, lines.get(0)); 119 } 120 } 121