156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/*
256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc.
356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License");
556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License.
656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at
756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0
956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software
1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS,
1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and
1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License.
1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage org.clearsilver.jni;
1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.File;
2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.regex.Pattern;
2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/**
2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Loads the ClearSilver JNI library.
2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p>By default, it attempts to load the library 'clearsilver-jni' from the
2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * path specified in the 'java.library.path' system property. However, this
2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * can be overriden by calling {@link #setLibraryName(String)} and
2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@link #setLibrarySearchPaths(String[])}.</p>
2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p>If this fails, the JVM exits with a code of 1. However, this strategy
3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * can be changed using {@link #setFailureCallback(Runnable)}.</p>
3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic final class JNI {
3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Failure callback strategy that writes a message to sysout, then calls
3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * System.exit(1).
3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static Runnable EXIT_JVM = new Runnable() {
4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public void run() {
4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      System.err.println("Could not load '" + libraryName + "'. Searched:");
4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      String platformLibraryName = System.mapLibraryName(libraryName);
4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      for (String path : librarySearchPaths) {
4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        System.err.println("  " +
4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson            new File(path, platformLibraryName).getAbsolutePath());
4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      System.err.println(
4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          "Try specifying -Djava.library.path=[directory] or calling "
4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson              + JNI.class.getName() + ".setLibrarySearchPaths(String...)");
5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      System.exit(1);
5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  };
5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Failure callback strategy that throws an UnsatisfiedLinkError, which
5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * should be caught be client code.
5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static Runnable THROW_ERROR = new Runnable() {
5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public void run() {
6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new UnsatisfiedLinkError("Could not load '" + libraryName + "'");
6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  };
6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private static Runnable failureCallback = EXIT_JVM;
6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private static Object callbackLock = new Object();
6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private static String libraryName = "clearsilver-jni";
6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private static String[] librarySearchPaths
7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      = System.getProperty("java.library.path", ".").split(
7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          Pattern.quote(File.pathSeparator));
7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private static volatile boolean successfullyLoadedLibrary;
7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Attempts to load the ClearSilver JNI library.
7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @see #setFailureCallback(Runnable)
8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static void loadLibrary() {
8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Library already loaded? Great - nothing to do.
8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (successfullyLoadedLibrary) {
8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return;
8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    synchronized (callbackLock) {
8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Search librarySearchPaths...
9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      String platformLibraryName = System.mapLibraryName(libraryName);
9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      for (String path : librarySearchPaths) {
9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        try {
9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // Attempt to load the library in that path.
9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          System.load(new File(path, platformLibraryName).getAbsolutePath());
9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // If we got here, it worked. We're done.
9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          successfullyLoadedLibrary = true;
9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          return;
9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        } catch (UnsatisfiedLinkError e) {
10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // Library not found. Continue loop.
10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        }
10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Still here? Couldn't load library. Fail.
10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (failureCallback != null) {
10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        failureCallback.run();
10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Sets a callback for what should happen if the JNI library cannot
11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * be loaded. The default is {@link #EXIT_JVM}.
11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @see #EXIT_JVM
11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @see #THROW_ERROR
11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static void setFailureCallback(Runnable failureCallback) {
12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    synchronized(callbackLock) {
12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      JNI.failureCallback = failureCallback;
12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Set name of JNI library to load. Default is 'clearsilver-jni'.
12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static void setLibraryName(String libraryName) {
12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JNI.libraryName = libraryName;
13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Sets locations where JNI library is searched.
13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static void setLibrarySearchPaths(String... paths) {
13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JNI.librarySearchPaths = paths;
13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson}
140