1 /*
   2  * Copyright (c) 2020, 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 package jdk.internal.loader;
  25 
  26 import java.lang.reflect.Constructor;
  27 import java.net.MalformedURLException;
  28 import java.net.URL;
  29 import java.net.URLClassLoader;
  30 import java.nio.file.Paths;
  31 
  32 public class NativeLibrariesTest implements Runnable {
  33     public static final String LIB_NAME = "nativeLibrariesTest";
  34     // increments when JNI_OnLoad and JNI_OnUnload is invoked.
  35     // This is only for JNI native library
  36     private static int loadedCount = 0;
  37     private static int unloadedCount = 0;
  38     /*
  39      * Called by JNI_OnLoad when the native library is unloaded
  40      */
  41     static void nativeLibraryLoaded() {
  42         loadedCount++;
  43     }
  44 
  45     /*
  46      * Called by JNI_OnUnload when the native library is unloaded
  47      */
  48     static void nativeLibraryUnloaded() {
  49         unloadedCount++;
  50     }
  51 
  52     private final NativeLibraries nativeLibraries;
  53     public NativeLibrariesTest() {
  54         this.nativeLibraries = NativeLibraries.rawNativeLibraries(NativeLibraries.class, true);
  55     }
  56 
  57     /*
  58      * Invoke by p.Test to load the same native library from different class loader
  59      */
  60     public void run() {
  61         load(true); // expect loading of native library succeed
  62     }
  63 
  64     public void runTest() throws Exception {
  65         NativeLibrary nl1 = nativeLibraries.loadLibrary(LIB_NAME);
  66         NativeLibrary nl2 = nativeLibraries.loadLibrary(LIB_NAME);
  67         assertTrue(nl1 != null && nl2 != null, "fail to load library");
  68         assertTrue(nl1 == nl2, nl1 + " != " + nl2);
  69         assertTrue(loadedCount == 0, "Native library loaded.  Expected: JNI_OnUnload not invoked");
  70         assertTrue(unloadedCount == 0, "native library never unloaded");
  71 
  72         // load successfully even from another loader
  73         loadWithCustomLoader();
  74 
  75         // unload the native library
  76         nativeLibraries.unload(nl1);
  77         assertTrue(unloadedCount == 0, "Native library unloaded.  Expected: JNI_OnUnload not invoked");
  78 
  79         // reload the native library and expect new NativeLibrary instance
  80         NativeLibrary nl3 = nativeLibraries.loadLibrary(LIB_NAME);
  81         assertTrue(nl1 != nl3, nl1 + " == " + nl3);
  82         assertTrue(loadedCount == 0, "Native library loaded.  Expected: JNI_OnUnload not invoked");
  83 
  84         // load successfully even from another loader
  85         loadWithCustomLoader();
  86     }
  87 
  88     public void unload() {
  89         NativeLibrary nl = nativeLibraries.loadLibrary(LIB_NAME);
  90         // unload the native library
  91         nativeLibraries.unload(nl);
  92         assertTrue(unloadedCount == 0, "Native library unloaded.  Expected: JNI_OnUnload not invoked");
  93     }
  94 
  95     public void load(boolean succeed) {
  96         NativeLibrary nl = nativeLibraries.loadLibrary(LIB_NAME);
  97         if (succeed) {
  98             assertTrue(nl != null, "fail to load library");
  99         } else {
 100             assertTrue(nl == null, "load library should fail");
 101         }
 102     }
 103 
 104     /*
 105      * Loads p.Test class with a new class loader and invokes the run() method.
 106      * p.Test::run invokes NativeLibrariesTest::run
 107      */
 108     private void loadWithCustomLoader() throws Exception {
 109         TestLoader loader = new TestLoader();
 110         Class<?> c = Class.forName("p.Test", true, loader);
 111         Constructor<?> ctr = c.getConstructor(Runnable.class);
 112         Runnable r = (Runnable) ctr.newInstance(this);
 113         r.run();
 114     }
 115 
 116     static class TestLoader extends URLClassLoader {
 117         static URL[] toURLs() {
 118             try {
 119                 return new URL[] { Paths.get("classes").toUri().toURL() };
 120             } catch (MalformedURLException e) {
 121                 throw new Error(e);
 122             }
 123         }
 124 
 125         TestLoader() {
 126             super("testloader", toURLs(), ClassLoader.getSystemClassLoader());
 127         }
 128     }
 129 
 130     static void assertTrue(boolean value, String msg) {
 131         if (!value) {
 132             throw new AssertionError(msg);
 133         }
 134     }
 135 }