Package org.jblas.util

Source Code of org.jblas.util.LibraryLoader

// --- BEGIN LICENSE BLOCK ---
/*
* Copyright (c) 2009, Mikio L. Braun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*
*     * Redistributions in binary form must reproduce the above
*       copyright notice, this list of conditions and the following
*       disclaimer in the documentation and/or other materials provided
*       with the distribution.
*
*     * Neither the name of the Technische Universität Berlin nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// --- END LICENSE BLOCK ---
package org.jblas.util;

import org.jblas.exceptions.UnsupportedArchitectureException;

import java.io.*;

/**
* Class which allows to load a dynamic file as resource (for example, from a
* jar-file)
*/
public class LibraryLoader {

  private Logger logger;
  private String libpath;

  private static File tempDir;

  static {
    final Logger logger = Logger.getLogger();

    try {
    tempDir = File.createTempFile("jblas", "");

    if (!tempDir.delete() || !tempDir.mkdir()) {
      throw new IOException(String.format("Couldn't create directory \"%s\"", tempDir.getAbsolutePath()));
    }

    Runtime.getRuntime().addShutdownHook(new Thread() {
      @Override
      public void run() {
        for (File f: tempDir.listFiles()) {
          logger.info("Deleting " + f.getAbsolutePath());
          if (!f.delete()) {
            logger.warning(String.format("Couldn't delete temporary file \"%s\"", f.getAbsolutePath()));
          }
        }
        logger.info("Deleting " + tempDir.getAbsolutePath());
        if (!tempDir.delete()) {
          logger.warning(String.format("Couldn't delete temporary directory \"%s\"", tempDir.getAbsolutePath()));
        }
      }
    });
    } catch(IOException ex) {
      logger.error("Couldn't create temporary directory: " + ex.getMessage());
    }
  }

  public LibraryLoader() {
    logger = Logger.getLogger();
    libpath = null;
  }

  /**
   * <p>Find the library <tt>libname</tt> as a resource, copy it to a tempfile
   * and load it using System.load(). The name of the library has to be the
   * base name, it is mapped to the corresponding system name using
   * System.mapLibraryName(). For example, the library "foo" is called "libfoo.so"
   * under Linux and "foo.dll" under Windows, but you just have to pass "foo"
   * the loadLibrary().</p>
   * <p/>
   * <p>I'm not quite sure if this doesn't open all kinds of security holes. Any ideas?</p>
   * <p/>
   * <p>This function reports some more information to the "org.jblas" logger at
   * the FINE level.</p>
   *
   * @param libname basename of the library
   * @throws UnsatisfiedLinkError if library cannot be founds
   */
  public void loadLibrary(String libname, boolean withFlavor) {
    // preload flavor libraries
    String flavor = null;
    if (withFlavor) {
      logger.debug("Preloading ArchFlavor library.");
      flavor = ArchFlavor.archFlavor();
      if (flavor != null && flavor.equals("sse2")) {
        throw new UnsupportedArchitectureException("Support for SSE2 processors stopped with version 1.2.2. Sorry.");
      }
    }
    logger.debug("Found flavor = '" + flavor + "'");

    libname = System.mapLibraryName(libname);

    /*
     * JDK 7 changed the ending for Mac OS from "jnilib" to "dylib".
     *
     * If that is the case, remap the filename.
     */
    String loadLibname = libname;
    if (libname.endsWith("dylib")) {
      loadLibname = libname.replace(".dylib", ".jnilib");
      logger.config("Replaced .dylib with .jnilib");
    }

    logger.debug("Attempting to load \"" + loadLibname + "\".");

    String[] paths = {
        fatJarLibraryPath("static", flavor),
        fatJarLibraryPath("dynamic", flavor),
    };

    InputStream is = findLibrary(paths, loadLibname);

    // Haven't found the lib anywhere? Throw a reception.
    if (is == null) {
      throw new UnsatisfiedLinkError("Couldn't find the resource " + loadLibname + ".");
    }

    logger.config("Loading " + loadLibname + " from " + libpath + ", copying to " + libname + ".");
    loadLibraryFromStream(libname, is);
  }

  private InputStream findLibrary(String[] paths, String libname) {
    InputStream is = null;
    for (String path : paths) {
      is = tryPath(path + libname);
      if (is != null) {
        logger.debug("Found " + libname + " in " + path);
        libpath = path;
        break;
      }
    }
    return is;
  }

  /**
   * Translate all those Windows to "Windows". ("Windows XP", "Windows Vista", "Windows 7", etc.)
   */
  private String unifyOSName(String osname) {
    if (osname.startsWith("Windows")) {
      return "Windows";
    }
    return osname;
  }

  /**
   * Compute the path to the library. The path is basically
   * "/" + os.name + "/" + os.arch + "/" + libname.
   */
  private String fatJarLibraryPath(String linkage, String flavor) {
    String sep = "/"; //System.getProperty("file.separator");
    String os_name = unifyOSName(System.getProperty("os.name"));
    String os_arch = System.getProperty("os.arch");
    String path = sep + "lib" + sep + linkage + sep + os_name + sep + os_arch + sep;
    if (null != flavor)
      path += flavor + sep;
    return path;
  }

  /**
   * Try to open a file at the given position.
   */
  private InputStream tryPath(String path) {
    Logger.getLogger().debug("Trying path \"" + path + "\".");
    return getClass().getResourceAsStream(path);
  }

  private File createTempFile(String name) throws IOException {
    return new File(tempDir + File.separator + name);
  }

  /**
   * Load a system library from a stream. Copies the library to a temp file
   * and loads from there.
   *
   * @param libname name of the library (just used in constructing the library name)
   * @param is      InputStream pointing to the library
   */
  private void loadLibraryFromStream(String libname, InputStream is) {
    try {
      File tempfile = createTempFile(libname);
      OutputStream os = new FileOutputStream(tempfile);

      logger.debug("tempfile.getPath() = " + tempfile.getPath());

      long savedTime = System.currentTimeMillis();

      // Leo says 8k block size is STANDARD ;)
      byte buf[] = new byte[8192];
      int len;
      while ((len = is.read(buf)) > 0) {
        os.write(buf, 0, len);
      }

      double seconds = (double) (System.currentTimeMillis() - savedTime) / 1e3;
      logger.debug("Copying took " + seconds + " seconds.");

      os.close();

      logger.debug("Loading library from " + tempfile.getPath() + ".");
      System.load(tempfile.getPath());
    } catch (IOException io) {
      logger.error("Could not create the temp file: " + io.toString() + ".\n");
    } catch (UnsatisfiedLinkError ule) {
      logger.error("Couldn't load copied link file: " + ule.toString() + ".\n");
      throw ule;
    }
  }
}
TOP

Related Classes of org.jblas.util.LibraryLoader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.