1 /* 2 * Copyright (C) 2010 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 org.clearsilver.jni; 18 19 import java.io.File; 20 import java.util.regex.Pattern; 21 22 /** 23 * Loads the ClearSilver JNI library. 24 * 25 * <p>By default, it attempts to load the library 'clearsilver-jni' from the 26 * path specified in the 'java.library.path' system property. However, this 27 * can be overriden by calling {@link #setLibraryName(String)} and 28 * {@link #setLibrarySearchPaths(String[])}.</p> 29 * 30 * <p>If this fails, the JVM exits with a code of 1. However, this strategy 31 * can be changed using {@link #setFailureCallback(Runnable)}.</p> 32 */ 33 public final class JNI { 34 35 /** 36 * Failure callback strategy that writes a message to sysout, then calls 37 * System.exit(1). 38 */ 39 public static Runnable EXIT_JVM = new Runnable() { 40 public void run() { 41 System.err.println("Could not load '" + libraryName + "'. Searched:"); 42 String platformLibraryName = System.mapLibraryName(libraryName); 43 for (String path : librarySearchPaths) { 44 System.err.println(" " + 45 new File(path, platformLibraryName).getAbsolutePath()); 46 } 47 System.err.println( 48 "Try specifying -Djava.library.path=[directory] or calling " 49 + JNI.class.getName() + ".setLibrarySearchPaths(String...)"); 50 System.exit(1); 51 } 52 }; 53 54 /** 55 * Failure callback strategy that throws an UnsatisfiedLinkError, which 56 * should be caught be client code. 57 */ 58 public static Runnable THROW_ERROR = new Runnable() { 59 public void run() { 60 throw new UnsatisfiedLinkError("Could not load '" + libraryName + "'"); 61 } 62 }; 63 64 private static Runnable failureCallback = EXIT_JVM; 65 66 private static Object callbackLock = new Object(); 67 68 private static String libraryName = "clearsilver-jni"; 69 70 private static String[] librarySearchPaths 71 = System.getProperty("java.library.path", ".").split( 72 Pattern.quote(File.pathSeparator)); 73 74 private static volatile boolean successfullyLoadedLibrary; 75 76 /** 77 * Attempts to load the ClearSilver JNI library. 78 * 79 * @see #setFailureCallback(Runnable) 80 */ loadLibrary()81 public static void loadLibrary() { 82 83 // Library already loaded? Great - nothing to do. 84 if (successfullyLoadedLibrary) { 85 return; 86 } 87 88 synchronized (callbackLock) { 89 90 // Search librarySearchPaths... 91 String platformLibraryName = System.mapLibraryName(libraryName); 92 for (String path : librarySearchPaths) { 93 try { 94 // Attempt to load the library in that path. 95 System.load(new File(path, platformLibraryName).getAbsolutePath()); 96 // If we got here, it worked. We're done. 97 successfullyLoadedLibrary = true; 98 return; 99 } catch (UnsatisfiedLinkError e) { 100 // Library not found. Continue loop. 101 } 102 } 103 104 // Still here? Couldn't load library. Fail. 105 if (failureCallback != null) { 106 failureCallback.run(); 107 } 108 } 109 110 } 111 112 /** 113 * Sets a callback for what should happen if the JNI library cannot 114 * be loaded. The default is {@link #EXIT_JVM}. 115 * 116 * @see #EXIT_JVM 117 * @see #THROW_ERROR 118 */ setFailureCallback(Runnable failureCallback)119 public static void setFailureCallback(Runnable failureCallback) { 120 synchronized(callbackLock) { 121 JNI.failureCallback = failureCallback; 122 } 123 } 124 125 /** 126 * Set name of JNI library to load. Default is 'clearsilver-jni'. 127 */ setLibraryName(String libraryName)128 public static void setLibraryName(String libraryName) { 129 JNI.libraryName = libraryName; 130 } 131 132 /** 133 * Sets locations where JNI library is searched. 134 */ setLibrarySearchPaths(String... paths)135 public static void setLibrarySearchPaths(String... paths) { 136 JNI.librarySearchPaths = paths; 137 } 138 139 } 140