1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.harmony.tests.java.lang; 19 20 import junit.framework.TestCase; 21 22 import java.io.IOException; 23 import java.io.InputStream; 24 import java.net.JarURLConnection; 25 import java.net.URL; 26 import java.util.Arrays; 27 import java.util.jar.JarFile; 28 import libcore.io.Streams; 29 30 public class ClassLoaderTest extends TestCase { 31 32 /** A resource known to be present in the boot classpath. */ 33 private static final String BOOT_RESOURCE_NAME = "java/util/logging/logging.properties"; 34 35 /** A resource known to be present in the classpath associated with the test class. */ 36 private static final String TEST_RESOURCE_NAME = ClassTest.RESOURCE_ABS_NAME; 37 38 private ClassLoader testClassLoader; 39 40 @Override setUp()41 public void setUp() throws Exception { 42 super.setUp(); 43 testClassLoader = getClass().getClassLoader(); 44 } 45 46 /** 47 * java.lang.ClassLoader#getSystemClassLoader() 48 */ test_getSystemClassLoader()49 public void test_getSystemClassLoader() { 50 // Test for method java.lang.ClassLoader 51 // java.lang.ClassLoader.getSystemClassLoader() 52 ClassLoader cl = ClassLoader.getSystemClassLoader(); 53 assertNotNull(cl); 54 55 // The SystemClassLoader's parent should be the Boot classloader, which is used to load 56 // the various libcore classes. 57 assertNotNull(cl.getParent()); 58 Class<?> libcoreClass = Integer.class; 59 assertSame(cl.getParent(), libcoreClass.getClassLoader()); 60 61 // It is difficult to test further because the CTS tests run as an instrumented TestCase. 62 // Android apps do not have a system classpath, and rely on an application classloader to 63 // load app classes and resources, not the System ClassLoader. The System ClassLoader is not 64 // usually the parent of the application class loader. 65 } 66 67 /** 68 * java.lang.ClassLoader#getSystemResource(java.lang.String) 69 */ test_getSystemResourceLjava_lang_String()70 public void test_getSystemResourceLjava_lang_String() { 71 // Test for method java.net.URL 72 // java.lang.ClassLoader.getSystemResource(java.lang.String) 73 74 // It is difficult to test this because the CTS tests run as an instrumented TestCase. 75 // Android apps do not have a system classpath, and rely on an application classloader to 76 // load app classes and resources, not the System ClassLoader. 77 } 78 79 /** 80 * java.lang.ClassLoader#getResource(java.lang.String) 81 */ test_testClassLoader_getResourceLjava_lang_String()82 public void test_testClassLoader_getResourceLjava_lang_String() { 83 // Test for method java.net.URL 84 // java.lang.ClassLoader.getResource(java.lang.String) 85 86 // Test basic class loader behavior for the ClassLoader that was used to load the test 87 // class while being deliberately vague about which classloader it actually is. 88 89 ClassLoader parentClassLoader = testClassLoader.getParent(); 90 assertNull(parentClassLoader.getResource(TEST_RESOURCE_NAME)); 91 assertGetResourceIsValid(parentClassLoader, BOOT_RESOURCE_NAME); 92 93 assertGetResourceIsValid(testClassLoader, TEST_RESOURCE_NAME); 94 assertGetResourceIsValid(testClassLoader, BOOT_RESOURCE_NAME); 95 } 96 97 /** 98 * java.lang.ClassLoader#getResourceAsStream(java.lang.String) 99 */ test_testClassLoader_getResourceAsStreamLjava_lang_String()100 public void test_testClassLoader_getResourceAsStreamLjava_lang_String() throws Exception { 101 // Test for method java.io.InputStream 102 // java.lang.ClassLoader.getResourceAsStream(java.lang.String) 103 104 // Test basic class loader behavior for the ClassLoader that was used to load the test 105 // class while being deliberately vague about which classloader it actually is. 106 107 ClassLoader parentClassLoader = testClassLoader.getParent(); 108 assertGetResourceAsStreamNotNull(parentClassLoader, BOOT_RESOURCE_NAME); 109 assertNull(parentClassLoader.getResourceAsStream(TEST_RESOURCE_NAME)); 110 111 assertGetResourceAsStreamNotNull(testClassLoader, BOOT_RESOURCE_NAME); 112 assertGetResourceAsStreamNotNull(testClassLoader, TEST_RESOURCE_NAME); 113 } 114 test_testClassLoader_loadClass()115 public void test_testClassLoader_loadClass() throws Exception { 116 // Test basic class loader behavior for the ClassLoader that was used to load the test 117 // class while being deliberately vague about which classloader it actually is. 118 String integerClassName = Integer.class.getName(); 119 String testClassName = ClassLoaderTest.class.getName(); 120 121 ClassLoader parentClassLoader = testClassLoader.getParent(); 122 assertSame(Integer.class, parentClassLoader.loadClass(integerClassName)); 123 try { 124 parentClassLoader.loadClass(testClassName); 125 fail(); 126 } catch (ClassNotFoundException expected) { 127 } 128 129 assertSame(Integer.class, testClassLoader.loadClass(integerClassName)); 130 assertSame(this.getClass(), testClassLoader.loadClass(testClassName)); 131 } 132 133 //Regression Test for JIRA-2047 test_testClassLoader_getResourceAsStream_withSharpChar()134 public void test_testClassLoader_getResourceAsStream_withSharpChar() throws Exception { 135 assertGetResourceAsStreamNotNull(testClassLoader, ClassTest.SHARP_RESOURCE_ABS_NAME); 136 } 137 testUncachedJarStreamBehavior()138 public void testUncachedJarStreamBehavior() throws Exception { 139 URL resourceFromJar = testClassLoader.getResource(TEST_RESOURCE_NAME); 140 JarURLConnection uncachedConnection = (JarURLConnection) resourceFromJar.openConnection(); 141 uncachedConnection.setUseCaches(false); 142 JarFile uncachedJarFile = uncachedConnection.getJarFile(); 143 InputStream is = uncachedConnection.getInputStream(); 144 is.close(); 145 146 assertTrue("Closing the stream should close a cached connection", 147 isJarUrlConnectClosed(uncachedConnection)); 148 149 // Closing the stream closes the JarFile. 150 assertTrue(isJarFileClosed(uncachedJarFile)); 151 } 152 testCachedJarStreamBehavior()153 public void testCachedJarStreamBehavior() throws Exception { 154 URL resourceFromJar = testClassLoader.getResource(TEST_RESOURCE_NAME); 155 JarURLConnection cachedConnection1 = (JarURLConnection) resourceFromJar.openConnection(); 156 assertTrue(cachedConnection1.getUseCaches()); 157 158 JarURLConnection cachedConnection2 = (JarURLConnection) resourceFromJar.openConnection(); 159 assertTrue(cachedConnection2.getUseCaches()); 160 161 InputStream is1 = cachedConnection1.getInputStream(); 162 byte[] resourceData1 = Streams.readFullyNoClose(is1); 163 is1.close(); 164 assertFalse("Closing the stream should not close a cached connection", 165 isJarUrlConnectClosed(cachedConnection1)); 166 167 InputStream is2 = cachedConnection2.getInputStream(); 168 byte[] resourceData2 = Streams.readFullyNoClose(is2); 169 is2.close(); 170 assertFalse("Closing the stream should not close a cached connection", 171 isJarUrlConnectClosed(cachedConnection2)); 172 173 assertEquals(Arrays.toString(resourceData1), Arrays.toString(resourceData2)); 174 } 175 testResourceJarFileBehavior()176 public void testResourceJarFileBehavior() throws Exception { 177 URL resourceFromJar = testClassLoader.getResource(TEST_RESOURCE_NAME); 178 JarURLConnection urlConnection1 = (JarURLConnection) resourceFromJar.openConnection(); 179 assertTrue(urlConnection1.getUseCaches()); 180 181 JarURLConnection urlConnection2 = (JarURLConnection) resourceFromJar.openConnection(); 182 assertTrue(urlConnection1.getUseCaches()); 183 assertNotSame(urlConnection1, urlConnection2); 184 185 JarURLConnection uncachedConnection = (JarURLConnection) resourceFromJar.openConnection(); 186 assertNotSame(uncachedConnection, urlConnection2); 187 uncachedConnection.setUseCaches(false); 188 189 JarFile jarFile1 = urlConnection1.getJarFile(); 190 JarFile jarFile2 = urlConnection2.getJarFile(); 191 // Note: This implies nobody should ever call JarFile.close() when caching is enabled. 192 // We cannot test this, because it will break later tests. 193 assertSame(jarFile1, jarFile2); 194 195 JarFile uncachedJarFile = uncachedConnection.getJarFile(); 196 assertNotSame(jarFile1, uncachedJarFile); 197 uncachedJarFile.close(); 198 199 assertFalse(isJarFileClosed(jarFile1)); 200 assertTrue(isJarFileClosed(uncachedJarFile)); 201 } 202 assertGetResourceAsStreamNotNull(ClassLoader classLoader, String resourceName)203 private static void assertGetResourceAsStreamNotNull(ClassLoader classLoader, 204 String resourceName) throws IOException { 205 InputStream is = null; 206 try { 207 is = classLoader.getResourceAsStream(resourceName); 208 assertNotNull(is); 209 } finally { 210 if (is != null) { 211 is.close(); 212 } 213 } 214 } 215 assertGetResourceIsValid(ClassLoader classLoader, String resourceName)216 private static void assertGetResourceIsValid(ClassLoader classLoader, String resourceName) { 217 java.net.URL u = classLoader.getResource(resourceName); 218 assertNotNull(u); 219 InputStream is = null; 220 try { 221 is = u.openStream(); 222 assertNotNull(is); 223 is.close(); 224 } catch (IOException e) { 225 fail("IOException getting stream for resource : " + e.getMessage()); 226 } 227 } 228 isJarFileClosed(JarFile jarFile)229 private static boolean isJarFileClosed(JarFile jarFile) { 230 // Indirectly detect that the JarFile has been closed. 231 try { 232 jarFile.getEntry("anyName"); 233 return false; 234 } catch (IllegalStateException expected) { 235 return true; 236 } 237 } 238 isJarUrlConnectClosed(JarURLConnection jarURLConnection)239 private static boolean isJarUrlConnectClosed(JarURLConnection jarURLConnection) 240 throws IOException { 241 // Indirectly detect that the jarURLConnection has been closed. 242 try { 243 jarURLConnection.getInputStream(); 244 return false; 245 } catch (IllegalStateException e) { 246 return true; 247 } 248 } 249 }