1 /* 2 * Copyright (c) 2010, 2014, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.glass.utils; 26 27 import java.io.File; 28 import java.net.URI; 29 import java.security.AccessController; 30 import java.security.PrivilegedAction; 31 import java.util.HashSet; 32 33 public class NativeLibLoader { 34 35 private static final HashSet<String> loaded = new HashSet<String>(); 36 37 public static synchronized void loadLibrary(String libname) { 38 if (!loaded.contains(libname)) { 39 loadLibraryInternal(libname); 40 loaded.add(libname); 41 } 42 } 43 44 private static boolean verbose = false; 45 46 private static boolean usingModules = false; 47 private static File libDir = null; 48 private static String libPrefix = ""; 49 private static String libSuffix = ""; 50 51 static { 52 AccessController.doPrivileged((PrivilegedAction<Object>) () -> { 53 verbose = Boolean.getBoolean("javafx.verbose"); 54 return null; 55 }); 56 } 57 58 private static String[] initializePath(String propname) { 59 String ldpath = System.getProperty(propname, ""); 60 String ps = File.pathSeparator; 61 int ldlen = ldpath.length(); 62 int i, j, n; 63 // Count the separators in the path 64 i = ldpath.indexOf(ps); 65 n = 0; 66 while (i >= 0) { 67 n++; 68 i = ldpath.indexOf(ps, i + 1); 69 } 70 71 // allocate the array of paths - n :'s = n + 1 path elements 72 String[] paths = new String[n + 1]; 73 74 // Fill the array with paths from the ldpath 75 n = i = 0; 76 j = ldpath.indexOf(ps); 77 while (j >= 0) { 78 if (j - i > 0) { 79 paths[n++] = ldpath.substring(i, j); 80 } else if (j - i == 0) { 81 paths[n++] = "."; 82 } 83 i = j + 1; 84 j = ldpath.indexOf(ps, i); 85 } 86 paths[n] = ldpath.substring(i, ldlen); 87 return paths; 88 } 89 90 private static void loadLibraryInternal(String libraryName) { 91 // Look for the library in the same directory as the jar file 92 // containing this class. 93 // If that fails, then try System.loadLibrary. 94 try { 95 // FIXME: We should eventually remove this legacy path, since 96 // it isn't applicable to Jigsaw. 97 loadLibraryFullPath(libraryName); 98 } catch (UnsatisfiedLinkError ex) { 99 if (verbose && !usingModules) { 100 System.err.println("WARNING: " + ex); 101 } 102 103 // NOTE: First attempt to load the libraries from the java.library.path. 104 // This allows FX to find more recent versions of the shared libraries 105 // from java.library.path instead of ones that might be part of the JRE 106 // 107 String [] libPath = initializePath("java.library.path"); 108 for (int i=0; i<libPath.length; i++) { 109 try { 110 String path = libPath[i]; 111 if (!path.endsWith(File.separator)) path += File.separator; 112 String fileName = System.mapLibraryName(libraryName); 113 File libFile = new File(path + fileName); 114 System.load(libFile.getAbsolutePath()); 115 if (verbose) { 116 System.err.println("Loaded " + libFile.getAbsolutePath() 117 + " from java.library.path"); 118 } 119 return; 120 } catch (UnsatisfiedLinkError ex3) { 121 // Fail silently and try the next directory in java.library.path 122 } 123 } 124 125 // Finally we will use System.loadLibrary. 126 try { 127 System.loadLibrary(libraryName); 128 if (verbose) { 129 System.err.println("System.loadLibrary(" 130 + libraryName + ") succeeded"); 131 } 132 } catch (UnsatisfiedLinkError ex2) { 133 //On iOS we link all libraries staticaly. Presence of library 134 //is recognized by existence of JNI_OnLoad_libraryname() C function. 135 //If libraryname contains hyphen, it needs to be translated 136 //to underscore to form valid C function indentifier. 137 if ("iOS".equals(System.getProperty("os.name")) 138 && libraryName.contains("-")) { 139 libraryName = libraryName.replace("-", "_"); 140 try { 141 System.loadLibrary(libraryName); 142 return; 143 } catch (UnsatisfiedLinkError ex3) { 144 throw ex3; 145 } 146 } 147 // Rethrow exception 148 throw ex2; 149 } 150 } 151 } 152 153 /** 154 * Load the native library from the same directory as the jar file 155 * containing this class. 156 */ 157 private static void loadLibraryFullPath(String libraryName) { 158 try { 159 if (usingModules) { 160 throw new UnsatisfiedLinkError("ignored"); 161 } 162 if (libDir == null) { 163 // Get the URL for this class, if it is a jar URL, then get the 164 // filename associated with it. 165 String theClassFile = "NativeLibLoader.class"; 166 Class theClass = NativeLibLoader.class; 167 String classUrlString = theClass.getResource(theClassFile).toString(); 168 if (classUrlString.startsWith("jrt:")) { 169 // Suppress warning messages 170 usingModules = true; 171 throw new UnsatisfiedLinkError("ignored"); 172 } 173 if (!classUrlString.startsWith("jar:file:") || classUrlString.indexOf('!') == -1) { 174 throw new UnsatisfiedLinkError("Invalid URL for class: " + classUrlString); 175 } 176 // Strip out the "jar:" and everything after and including the "!" 177 String tmpStr = classUrlString.substring(4, classUrlString.lastIndexOf('!')); 178 // Strip everything after the last "/" or "\" to get rid of the jar filename 179 int lastIndexOfSlash = Math.max(tmpStr.lastIndexOf('/'), tmpStr.lastIndexOf('\\')); 180 181 // Set the native directory based on the OS 182 String osName = System.getProperty("os.name"); 183 String relativeDir = null; 184 if (osName.startsWith("Windows")) { 185 relativeDir = "../bin"; 186 } else if (osName.startsWith("Mac")) { 187 relativeDir = "."; 188 } else if (osName.startsWith("Linux")) { 189 relativeDir = "./" + System.getProperty("os.arch"); 190 } 191 192 // Location of native libraries relative to jar file 193 String libDirUrlString = tmpStr.substring(0, lastIndexOfSlash) 194 + "/" + relativeDir; 195 libDir = new File(new URI(libDirUrlString).getPath()); 196 197 // Set the lib prefix and suffix based on the OS 198 if (osName.startsWith("Windows")) { 199 libPrefix = ""; 200 libSuffix = ".dll"; 201 } else if (osName.startsWith("Mac")) { 202 libPrefix = "lib"; 203 libSuffix = ".dylib"; 204 } else if (osName.startsWith("Linux")) { 205 libPrefix = "lib"; 206 libSuffix = ".so"; 207 } 208 } 209 210 File libFile = new File(libDir, libPrefix + libraryName + libSuffix); 211 String libFileName = libFile.getCanonicalPath(); 212 try { 213 System.load(libFileName); 214 if (verbose) { 215 System.err.println("Loaded " + libFile.getAbsolutePath() 216 + " from relative path"); 217 } 218 } catch(UnsatisfiedLinkError ex) { 219 throw ex; 220 } 221 } catch (Exception e) { 222 // Throw UnsatisfiedLinkError for best compatibility with System.loadLibrary() 223 throw (UnsatisfiedLinkError) new UnsatisfiedLinkError().initCause(e); 224 } 225 } 226 }