001package com.github.sarxos.webcam.ds.civil; 002 003import java.io.File; 004import java.io.FileNotFoundException; 005import java.io.FileOutputStream; 006import java.io.IOException; 007import java.io.InputStream; 008import java.io.OutputStream; 009 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013 014public class LtiCivilLoader { 015 016 private static final Logger LOG = LoggerFactory.getLogger(LtiCivilLoader.class); 017 018 /** 019 * Will be called until JVM shutdown. 020 * 021 * @author Bartosz Firyn (SarXos) 022 */ 023 private static class Deleter extends Thread { 024 025 private File file = null; 026 027 public Deleter(File file) { 028 super("lti-civil-binary-deleter"); 029 this.file = file; 030 } 031 032 @Override 033 public void run() { 034 super.run(); 035 if (file.exists()) { 036 if (!file.delete()) { 037 LOG.warn(String.format("JVM was not able to remove file %s", file)); 038 } 039 } 040 } 041 } 042 043 private LtiCivilLoader() { 044 // singleton 045 } 046 047 /** 048 * Copy bytes from a large (over 2GB) InputStream to an OutputStream. 049 * 050 * @param input the InputStream to read from 051 * @param output the OutputStream to write to 052 * @return the number of bytes copied 053 * @throws NullPointerException if the input or output is null 054 * @throws IOException if an I/O error occurs 055 */ 056 private static long copy(InputStream input, OutputStream output) throws IOException { 057 byte[] buffer = new byte[1024 * 4]; 058 long count = 0; 059 int n = 0; 060 while (-1 != (n = input.read(buffer))) { 061 output.write(buffer, 0, n); 062 count += n; 063 } 064 return count; 065 } 066 067 protected static void load(String lib) { 068 LOG.info("Loading native library: " + lib); 069 try { 070 System.loadLibrary(lib); 071 LOG.info("DLL has been loaded from memory: " + lib); 072 } catch (UnsatisfiedLinkError e) { 073 try { 074 load("civil-" + System.currentTimeMillis(), lib); 075 } catch (Exception e2) { 076 LOG.error("Exception when loading DLL library", e2); 077 throw new RuntimeException(e2); 078 } 079 } 080 } 081 082 protected static void load(String path, String name) { 083 084 String libroot = "/META-INF/lib"; 085 String libpath = null; 086 String libfile = null; 087 088 boolean arch64 = System.getProperty("os.arch").indexOf("64") != -1; 089 boolean linux = System.getProperty("os.name").toLowerCase().indexOf("linux") != -1; 090 091 if (linux) { 092 libpath = libroot + (arch64 ? "/linux64/" : "/linux32/"); 093 libfile = "lib" + name + ".so"; 094 } else { 095 libpath = libroot + (arch64 ? "/win64/" : "/win32/"); 096 libfile = name + ".dll"; 097 } 098 099 File parent = new File(System.getProperty("java.io.tmpdir") + "/" + path); 100 if (!parent.exists()) { 101 if (!parent.mkdirs()) { 102 throw new RuntimeException("Cannot create directory: " + parent.getAbsolutePath()); 103 } 104 } 105 106 File file = new File(parent, libfile); 107 if (!file.exists()) { 108 109 boolean created = false; 110 try { 111 created = file.createNewFile(); 112 } catch (IOException e) { 113 throw new RuntimeException("Not able to create file: " + file, e); 114 } 115 if (!created) { 116 throw new RuntimeException("File cannot be created: " + file); 117 } 118 119 Runtime.getRuntime().addShutdownHook(new Deleter(file)); 120 } 121 122 String resource = libpath + libfile; 123 124 LOG.debug("Library resource in JAR is {}", resource); 125 126 InputStream in = LtiCivilDriver.class.getResourceAsStream(resource); 127 if (in == null) { 128 throw new RuntimeException("Resource not found: " + resource); 129 } 130 131 FileOutputStream fos = null; 132 133 try { 134 fos = new FileOutputStream(file); 135 copy(in, fos); 136 } catch (FileNotFoundException e) { 137 throw new RuntimeException("File not found " + file, e); 138 } catch (IOException e) { 139 throw new RuntimeException("IO exception", e); 140 } finally { 141 if (in != null) { 142 try { 143 in.close(); 144 } catch (IOException e) { 145 throw new RuntimeException("Cannot close input stream", e); 146 } 147 } 148 if (fos != null) { 149 try { 150 fos.close(); 151 } catch (IOException e) { 152 throw new RuntimeException("Cannot close file output stream", e); 153 } 154 } 155 } 156 157 LOG.debug("Loading library from file {}", file); 158 159 try { 160 System.load(file.getAbsolutePath()); 161 } catch (UnsatisfiedLinkError e) { 162 throw new RuntimeException("Library file cannot be loaded: " + file, e); 163 } 164 } 165}