1/* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/** 25 * @test 26 * @summary Basic test for redefineModule 27 * 28 * @build java.base/java.lang.TestProvider 29 * java.base/jdk.internal.test.TestProviderImpl1 30 * java.base/jdk.internal.test.TestProviderImpl2 31 * @run shell MakeJAR3.sh RedefineModuleAgent 32 * @run testng/othervm --illegal-access=deny -javaagent:RedefineModuleAgent.jar RedefineModuleTest 33 */ 34 35import java.lang.TestProvider; 36import java.lang.instrument.Instrumentation; 37import java.net.URLStreamHandler; 38import java.net.spi.URLStreamHandlerProvider; 39import java.nio.file.FileSystems; 40import java.util.ArrayList; 41import java.util.Collection; 42import java.util.HashMap; 43import java.util.HashSet; 44import java.util.List; 45import java.util.Map; 46import java.util.ServiceLoader; 47import java.util.Set; 48 49import org.testng.annotations.Test; 50import static org.testng.Assert.*; 51 52@Test 53public class RedefineModuleTest { 54 55 static void redefineModule(Module module, 56 Set<Module> extraReads, 57 Map<String, Set<Module>> extraExports, 58 Map<String, Set<Module>> extraOpens, 59 Set<Class<?>> extraUses, 60 Map<Class<?>, List<Class<?>>> extraProvides) { 61 RedefineModuleAgent.redefineModule(module, 62 extraReads, 63 extraExports, 64 extraOpens, 65 extraUses, 66 extraProvides); 67 } 68 69 static boolean isModifiableModule(Module module) { 70 return RedefineModuleAgent.isModifiableModule(module); 71 } 72 73 74 /** 75 * Use redefineModule to update java.base to read java.instrument 76 */ 77 public void testAddReads() { 78 Module baseModule = Object.class.getModule(); 79 Module instrumentModule = Instrumentation.class.getModule(); 80 81 // pre-conditions 82 assertFalse(baseModule.canRead(instrumentModule)); 83 84 // update java.base to read java.instrument 85 Set<Module> extraReads = Set.of(instrumentModule); 86 redefineModule(baseModule, extraReads, Map.of(), Map.of(), Set.of(), Map.of()); 87 assertTrue(baseModule.canRead(instrumentModule)); 88 } 89 90 /** 91 * Use redefineModule to update java.base to export jdk.internal.misc 92 */ 93 public void testAddExports() { 94 Module baseModule = Object.class.getModule(); 95 Module thisModule = this.getClass().getClassLoader().getUnnamedModule(); 96 String pkg = "jdk.internal.misc"; 97 98 // pre-conditions 99 assertFalse(baseModule.isExported(pkg)); 100 assertFalse(baseModule.isExported(pkg, thisModule)); 101 102 // update java.base to export jdk.internal.misc to an unnamed module 103 Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of(thisModule)); 104 redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); 105 assertFalse(baseModule.isExported(pkg)); 106 assertTrue(baseModule.isExported(pkg, thisModule)); 107 assertFalse(baseModule.isOpen(pkg)); 108 assertFalse(baseModule.isOpen(pkg, thisModule)); 109 } 110 111 /** 112 * Use redefineModule to update java.base to open jdk.internal.loader 113 */ 114 public void testAddOpens() { 115 Module baseModule = Object.class.getModule(); 116 Module thisModule = this.getClass().getClassLoader().getUnnamedModule(); 117 String pkg = "jdk.internal.loader"; 118 119 // pre-conditions 120 assertFalse(baseModule.isOpen(pkg)); 121 assertFalse(baseModule.isOpen(pkg, thisModule)); 122 123 // update java.base to open dk.internal.loader to an unnamed module 124 Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of(thisModule)); 125 redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of()); 126 assertFalse(baseModule.isExported(pkg)); 127 assertTrue(baseModule.isExported(pkg, thisModule)); 128 assertFalse(baseModule.isOpen(pkg)); 129 assertTrue(baseModule.isOpen(pkg, thisModule)); 130 } 131 132 /** 133 * Use redefineModule to update java.base to use TestProvider and 134 * provide implementations of TestProvider. 135 */ 136 public void testAddUsesAndProvides() throws Exception { 137 Module baseModule = Object.class.getModule(); 138 Class<TestProvider> service = TestProvider.class; 139 140 // pre-conditions 141 assertFalse(baseModule.canUse(service)); 142 assertTrue(collect(ServiceLoader.load(service)).isEmpty()); 143 assertTrue(collect(ServiceLoader.load(ModuleLayer.boot(), service)).isEmpty()); 144 145 // update java.base to use TestProvider 146 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(service), Map.of()); 147 assertTrue(baseModule.canUse(service)); 148 assertTrue(collect(ServiceLoader.load(service)).isEmpty()); 149 assertTrue(collect(ServiceLoader.load(ModuleLayer.boot(), service)).isEmpty()); 150 151 // update java.base to provide an implementation of TestProvider 152 Class<?> type1 = Class.forName("jdk.internal.test.TestProviderImpl1"); 153 Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of(type1)); 154 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); 155 156 // invoke ServiceLoader from java.base to find providers 157 Set<TestProvider> providers = collect(TestProvider.providers()); 158 assertTrue(providers.size() == 1); 159 assertTrue(containsInstanceOf(providers, type1)); 160 161 // use ServiceLoader to load implementations visible via TCCL 162 providers = collect(ServiceLoader.load(service)); 163 assertTrue(collect(providers).size() == 1); 164 assertTrue(containsInstanceOf(collect(providers), type1)); 165 166 // use ServiceLoader to load implementations in the boot layer 167 providers = collect(ServiceLoader.load(ModuleLayer.boot(), service)); 168 assertTrue(collect(providers).size() == 1); 169 assertTrue(containsInstanceOf(collect(providers), type1)); 170 171 // update java.base to provide a second implementation of TestProvider 172 Class<?> type2 = Class.forName("jdk.internal.test.TestProviderImpl2"); 173 extraProvides = Map.of(service, List.of(type2)); 174 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); 175 176 // invoke ServiceLoader from java.base to find providers 177 providers = collect(TestProvider.providers()); 178 assertTrue(providers.size() == 2); 179 assertTrue(containsInstanceOf(providers, type1)); 180 assertTrue(containsInstanceOf(providers, type2)); 181 182 // use ServiceLoader to load implementations visible via TCCL 183 providers = collect(ServiceLoader.load(service)); 184 assertTrue(collect(providers).size() == 2); 185 assertTrue(containsInstanceOf(providers, type1)); 186 assertTrue(containsInstanceOf(providers, type2)); 187 188 // use ServiceLoader to load implementations in the boot layer 189 providers = collect(ServiceLoader.load(ModuleLayer.boot(), service)); 190 assertTrue(collect(providers).size() == 2); 191 assertTrue(containsInstanceOf(providers, type1)); 192 assertTrue(containsInstanceOf(providers, type2)); 193 } 194 195 private <S> Set<S> collect(Iterable<S> sl) { 196 Set<S> providers = new HashSet<>(); 197 sl.forEach(providers::add); 198 return providers; 199 } 200 201 private boolean containsInstanceOf(Collection<?> c, Class<?> type) { 202 for (Object o : c) { 203 if (type.isInstance(o)) return true; 204 } 205 return false; 206 } 207 208 @Test(expectedExceptions = IllegalArgumentException.class) 209 public void testExportPackageToEmptySet() { 210 // attempt to update java.base to export jdk.internal.misc to nobody 211 Module baseModule = Object.class.getModule(); 212 Map<String, Set<Module>> extraExports = Map.of("jdk.internal.misc", Set.of()); 213 redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); 214 } 215 216 @Test(expectedExceptions = IllegalArgumentException.class) 217 public void testOpenPackageToEmptySet() { 218 // attempt to update java.base to open jdk.internal.misc to nobody 219 Module baseModule = Object.class.getModule(); 220 Map<String, Set<Module>> extraOpens = Map.of("jdk.internal.misc", Set.of()); 221 redefineModule(baseModule, Set.of(), Map.of(), extraOpens, Set.of(), Map.of()); 222 } 223 224 @Test(expectedExceptions = IllegalArgumentException.class) 225 public void testProvideServiceWithEmptyList() throws Exception { 226 // update java.base to provide an empty list of TestProvider 227 Module baseModule = Object.class.getModule(); 228 Class<?> service = TestProvider.class; 229 Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of()); 230 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); 231 } 232 233 /** 234 * Test redefineClass by attempting to update java.base to export a package 235 * that it does not contain. 236 */ 237 @Test(expectedExceptions = IllegalArgumentException.class) 238 public void testExportPackageNotInModule() { 239 Module baseModule = Object.class.getModule(); 240 String pkg = "jdk.doesnotexist"; 241 242 // attempt to update java.base to export jdk.doesnotexist 243 Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of()); 244 redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); 245 } 246 247 /** 248 * Test redefineClass by attempting to update java.base to provide a service 249 * where the service provider class is not in the module. 250 */ 251 @Test(expectedExceptions = IllegalArgumentException.class) 252 public void testProvideServiceNotInModule() { 253 Module baseModule = Object.class.getModule(); 254 class MyProvider extends URLStreamHandlerProvider { 255 @Override 256 public URLStreamHandler createURLStreamHandler(String protocol) { 257 return null; 258 } 259 } 260 261 // attempt to update java.base to provide MyProvider 262 Map<Class<?>, List<Class<?>>> extraProvides 263 = Map.of(URLStreamHandlerProvider.class, List.of(MyProvider.class)); 264 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); 265 } 266 267 /** 268 * Test redefineClass by attempting to update java.base to provide a 269 * service where the service provider class is not a sub-type. 270 */ 271 @Test(expectedExceptions = IllegalArgumentException.class) 272 public void testProvideServiceNotSubtype() { 273 Module baseModule = Object.class.getModule(); 274 275 Class<?> service = TestProvider.class; 276 Class<?> impl = FileSystems.getDefault().provider().getClass(); 277 278 // attempt to update java.base to provide an implementation of TestProvider 279 Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of(impl)); 280 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); 281 } 282 283 /** 284 * Exercise IsModifiableModule 285 */ 286 @Test 287 public void testIsModifiableModule() { 288 ClassLoader pcl = ClassLoader.getPlatformClassLoader(); 289 ClassLoader scl = ClassLoader.getSystemClassLoader(); 290 assertTrue(isModifiableModule(pcl.getUnnamedModule())); 291 assertTrue(isModifiableModule(scl.getUnnamedModule())); 292 assertTrue(isModifiableModule(RedefineModuleTest.class.getModule())); 293 assertTrue(isModifiableModule(Object.class.getModule())); 294 } 295 296 /** 297 * Test redefineClass with null 298 */ 299 public void testNulls() { 300 Module baseModule = Object.class.getModule(); 301 302 try { 303 redefineModule(null, Set.of(), Map.of(), Map.of(), Set.of(), Map.of()); 304 assertTrue(false); 305 } catch (NullPointerException e) { } 306 307 try { 308 redefineModule(baseModule, null, Map.of(), Map.of(), Set.of(), Map.of()); 309 assertTrue(false); 310 } catch (NullPointerException e) { } 311 312 try { 313 redefineModule(baseModule, Set.of(), null, Map.of(), Set.of(), Map.of()); 314 assertTrue(false); 315 } catch (NullPointerException e) { } 316 317 try { 318 redefineModule(baseModule, Set.of(), Map.of(), null, Set.of(), Map.of()); 319 assertTrue(false); 320 } catch (NullPointerException e) { } 321 322 try { 323 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), null, Map.of()); 324 assertTrue(false); 325 } catch (NullPointerException e) { } 326 327 try { 328 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), null); 329 assertTrue(false); 330 } catch (NullPointerException e) { } 331 332 try { 333 Set<Module> containsNull = new HashSet<>(); 334 containsNull.add(null); 335 redefineModule(baseModule, containsNull, Map.of(), Map.of(), Set.of(), Map.of()); 336 assertTrue(false); 337 } catch (NullPointerException e) { } 338 339 try { 340 Map<String, Set<Module>> extraExports = new HashMap<>(); 341 extraExports.put(null, Set.of()); 342 redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); 343 assertTrue(false); 344 } catch (NullPointerException e) { } 345 346 try { 347 Map<String, Set<Module>> extraExports = new HashMap<>(); 348 extraExports.put(null, Set.of()); 349 redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of()); 350 assertTrue(false); 351 } catch (NullPointerException e) { } 352 353 try { 354 Set<Module> containsNull = new HashSet<>(); 355 containsNull.add(null); 356 Map<String, Set<Module>> extraExports = Map.of("java.lang", containsNull); 357 redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); 358 assertTrue(false); 359 } catch (NullPointerException e) { } 360 361 try { 362 Set<Class<?>> containsNull = new HashSet<>(); 363 containsNull.add(null); 364 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), containsNull, Map.of()); 365 assertTrue(false); 366 } catch (NullPointerException e) { } 367 368 try { 369 Map<Class<?>, List<Class<?>>> extraProvides = new HashMap<>(); 370 extraProvides.put(null, List.of()); 371 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); 372 assertTrue(false); 373 } catch (NullPointerException e) { } 374 375 try { 376 List<Class<?>> containsNull = new ArrayList<>(); 377 containsNull.add(null); 378 Map<Class<?>, List<Class<?>>> extraProvides = Map.of(TestProvider.class, containsNull); 379 redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); 380 assertTrue(false); 381 } catch (NullPointerException e) { } 382 } 383 384} 385