Simplified loading native libraries
This commit is contained in:
parent
3856925cb2
commit
ce4e3bef90
|
@ -10,6 +10,7 @@ package com.barchart.udt;
|
|||
import com.barchart.udt.anno.Native;
|
||||
import com.barchart.udt.nio.KindUDT;
|
||||
import com.barchart.udt.util.HelpUDT;
|
||||
import dorkbox.network.util.NativeLoader;
|
||||
import dorkbox.util.FileUtil;
|
||||
import dorkbox.util.OS;
|
||||
import dorkbox.util.OsType;
|
||||
|
@ -17,30 +18,16 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.security.CodeSource;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* UDT native socket wrapper
|
||||
|
@ -159,87 +146,32 @@ class SocketUDT {
|
|||
if (isContainer) {
|
||||
// have to extract our correct file to temp then load it, ONLY if we are not already loaded!
|
||||
|
||||
String sourceFileName = "udt-core-2.3.2";
|
||||
if (OS.isLinux()) {
|
||||
sourceFileName += ".so";
|
||||
}
|
||||
else if (OS.isWindows()) {
|
||||
sourceFileName += ".dll";
|
||||
}
|
||||
else {
|
||||
sourceFileName += ".dylib";
|
||||
}
|
||||
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
digest.update(TypeUDT.class.getName()
|
||||
.getBytes());
|
||||
|
||||
// convert to alpha-numeric. see https://stackoverflow.com/questions/29183818/why-use-tostring32-and-not-tostring36
|
||||
final String outputFileName = "UDT_driver_" + new BigInteger(1, digest.digest()).toString(32)
|
||||
.toUpperCase(Locale.US);
|
||||
|
||||
final String tempDir = System.getProperty("java.io.tmpdir");
|
||||
|
||||
final File file = new File(tempDir, outputFileName);
|
||||
if (!file.canRead()) {
|
||||
// we need to iterate this jar to get the files
|
||||
|
||||
final String packageName = TypeUDT.class.getPackage()
|
||||
.getName()
|
||||
.replaceAll("\\.", "/");
|
||||
|
||||
final String prefix = packageName + "/natives/" + osName + "/";
|
||||
final List<String> list = Arrays.asList(os.getLibraryNames());
|
||||
|
||||
final String jarFileName = URLDecoder.decode(loc.getPath(), "UTF-8");
|
||||
JarFile jar = new JarFile(jarFileName);
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
JAR_READ:
|
||||
while (entries.hasMoreElements()) {
|
||||
final JarEntry jarEntry = entries.nextElement();
|
||||
String name = jarEntry.getName();
|
||||
|
||||
if (name.startsWith(prefix)) {
|
||||
for (String s : list) {
|
||||
if (name.endsWith(s)) {
|
||||
// there is only one!
|
||||
|
||||
// now we copy it out
|
||||
final InputStream inputStream = jar.getInputStream(jarEntry);
|
||||
|
||||
OutputStream outStream = null;
|
||||
try {
|
||||
outStream = new FileOutputStream(file);
|
||||
|
||||
byte[] buffer = new byte[2048];
|
||||
int read;
|
||||
while ((read = inputStream.read(buffer)) > 0) {
|
||||
outStream.write(buffer, 0, read);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Error extracting library from: " + jarFileName, e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
if (outStream != null) {
|
||||
outStream.close();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
break JAR_READ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jar.close();
|
||||
}
|
||||
|
||||
log.info("Loading release libraries.");
|
||||
|
||||
System.load(file.getAbsolutePath());
|
||||
final String packageName = TypeUDT.class.getPackage()
|
||||
.getName()
|
||||
.replaceAll("\\.", "/");
|
||||
|
||||
sourceFileName = packageName + "/natives/" + osName + "/" + sourceFileName;
|
||||
|
||||
NativeLoader.loadLibrary(sourceFileName, "networkUDT_", TypeUDT.class);
|
||||
|
||||
log.info("Release libraries loaded.");
|
||||
loaded = true;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
log.error("Error loading MD5 checksum.", e.getMessage());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.error("Error parsing text.", e.getMessage());
|
||||
} catch (IOException e) {
|
||||
log.error("Error extracting library.", e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
162
src/dorkbox/network/util/NativeLinuxEpoll.java
Normal file
162
src/dorkbox/network/util/NativeLinuxEpoll.java
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright 2016 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package dorkbox.network.util;
|
||||
|
||||
/**
|
||||
* The contents of this method are used to rewrite (via javassist, via the BuildDependencyJars build) the NativeLibraryLoader.load method.
|
||||
*
|
||||
* This is necessary so that we don't continuously recreate the native library every time we start.
|
||||
*
|
||||
* Also, this file is not included in the build process.
|
||||
*/
|
||||
public
|
||||
class NativeLinuxEpoll {
|
||||
|
||||
public static
|
||||
void load(String name, ClassLoader loader) {
|
||||
// try {
|
||||
// String var0 = $1;
|
||||
// ClassLoader var1 = $2;
|
||||
// if (var0.equals("netty-transport-native-epoll")) {
|
||||
// String sourceFileName = "META-INF/native/lib" + var0 + ".so";
|
||||
// String suffix = ".so";
|
||||
//
|
||||
// String version = dorkbox.network.Server.getVersion();
|
||||
//
|
||||
// final String outputFileName = "lib" + var0 + "." + version + suffix;
|
||||
// final String tempDir = System.getProperty("java.io.tmpdir");
|
||||
//
|
||||
// final java.io.File file = new java.io.File(tempDir, outputFileName);
|
||||
// if (!file.canRead()) {
|
||||
// java.net.URL url = var1.getResource(sourceFileName);
|
||||
//
|
||||
// System.err.println("Loading: " + file.getAbsolutePath());
|
||||
//
|
||||
// // now we copy it out
|
||||
// final java.io.InputStream inputStream = url.openStream();
|
||||
//
|
||||
// java.io.OutputStream outStream = null;
|
||||
// try {
|
||||
// outStream = new java.io.FileOutputStream(file);
|
||||
//
|
||||
// byte[] buffer = new byte[4096];
|
||||
// int read;
|
||||
// while ((read = inputStream.read(buffer)) > 0) {
|
||||
// outStream.write(buffer, 0, read);
|
||||
// }
|
||||
//
|
||||
// outStream.flush();
|
||||
// outStream.close();
|
||||
// outStream = null;
|
||||
// } finally {
|
||||
// try {
|
||||
// inputStream.close();
|
||||
// } catch (Exception ignored) {
|
||||
// }
|
||||
// try {
|
||||
// if (outStream != null) {
|
||||
// outStream.close();
|
||||
// }
|
||||
// } catch (Exception ignored) {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// System.load(file.getAbsolutePath());
|
||||
// }
|
||||
// else {
|
||||
// // default file operation
|
||||
//
|
||||
// String libname = System.mapLibraryName(var0);
|
||||
// String path = io.netty.util.internal.NativeLibraryLoader.NATIVE_RESOURCE_HOME + libname;
|
||||
//
|
||||
// java.net.URL url = var1.getResource(path);
|
||||
// if (url == null && io.netty.util.internal.NativeLibraryLoader.isOSX()) {
|
||||
// if (path.endsWith(".jnilib")) {
|
||||
// url = var1.getResource(io.netty.util.internal.NativeLibraryLoader.NATIVE_RESOURCE_HOME + "lib" + var0 + ".dynlib");
|
||||
// }
|
||||
// else {
|
||||
// url = var1.getResource(io.netty.util.internal.NativeLibraryLoader.NATIVE_RESOURCE_HOME + "lib" + var0 + ".jnilib");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (url == null) {
|
||||
// // Fall back to normal loading of JNI stuff
|
||||
// System.loadLibrary(var0);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// int index = libname.lastIndexOf('.');
|
||||
// String prefix = libname.substring(0, index);
|
||||
// String suffix = libname.substring(index, libname.length());
|
||||
// java.io.InputStream in = null;
|
||||
// java.io.OutputStream out = null;
|
||||
// java.io.File tmpFile = null;
|
||||
// boolean loaded = false;
|
||||
// try {
|
||||
// tmpFile = java.io.File.createTempFile(prefix, suffix, io.netty.util.internal.NativeLibraryLoader.WORKDIR);
|
||||
// in = url.openStream();
|
||||
// out = new java.io.FileOutputStream(tmpFile);
|
||||
//
|
||||
// byte[] buffer = new byte[8192];
|
||||
// int length;
|
||||
// while ((length = in.read(buffer)) > 0) {
|
||||
// out.write(buffer, 0, length);
|
||||
// }
|
||||
// out.flush();
|
||||
// out.close();
|
||||
// out = null;
|
||||
//
|
||||
// System.load(tmpFile.getPath());
|
||||
// loaded = true;
|
||||
// } catch (Exception e) {
|
||||
// throw (UnsatisfiedLinkError) new UnsatisfiedLinkError("could not load a native library: " + var0).initCause(e);
|
||||
// } finally {
|
||||
// if (in != null) {
|
||||
// try {
|
||||
// in.close();
|
||||
// } catch (java.io.IOException ignore) {
|
||||
// // ignore
|
||||
// }
|
||||
// }
|
||||
// if (out != null) {
|
||||
// try {
|
||||
// out.close();
|
||||
// } catch (java.io.IOException ignore) {
|
||||
// // ignore
|
||||
// }
|
||||
// }
|
||||
// if (tmpFile != null) {
|
||||
// if (loaded) {
|
||||
// tmpFile.deleteOnExit();
|
||||
// }
|
||||
// else {
|
||||
// if (!tmpFile.delete()) {
|
||||
// tmpFile.deleteOnExit();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
}
|
||||
|
||||
private
|
||||
NativeLinuxEpoll() {
|
||||
}
|
||||
}
|
96
src/dorkbox/network/util/NativeLoader.java
Normal file
96
src/dorkbox/network/util/NativeLoader.java
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright 2016 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package dorkbox.network.util;
|
||||
|
||||
import dorkbox.network.Server;
|
||||
import dorkbox.util.OS;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.rmi.server.ExportException;
|
||||
|
||||
/**
|
||||
* Loads the specified library, extracting it from the jar, if necessary
|
||||
*/
|
||||
public
|
||||
class NativeLoader {
|
||||
|
||||
public static
|
||||
void loadLibrary(final String sourceFileName, final String destinationPrefix, final Class<?> classLoaderClass) throws Exception {
|
||||
try {
|
||||
String suffix;
|
||||
if (OS.isLinux()) {
|
||||
suffix = ".so";
|
||||
}
|
||||
else if (OS.isWindows()) {
|
||||
suffix = ".dll";
|
||||
}
|
||||
else {
|
||||
suffix = ".dylib";
|
||||
}
|
||||
|
||||
final String outputFileName = destinationPrefix + "." + Server.getVersion() + suffix;
|
||||
final String tempDir = System.getProperty("java.io.tmpdir");
|
||||
|
||||
final File file = new File(tempDir, outputFileName);
|
||||
if (!file.canRead()) {
|
||||
ClassLoader loader = PlatformDependent.getClassLoader(classLoaderClass);
|
||||
URL url = loader.getResource(sourceFileName);
|
||||
|
||||
// now we copy it out
|
||||
final InputStream inputStream = url.openStream();
|
||||
|
||||
OutputStream outStream = null;
|
||||
try {
|
||||
outStream = new FileOutputStream(file);
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
while ((read = inputStream.read(buffer)) > 0) {
|
||||
outStream.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
outStream.flush();
|
||||
outStream.close();
|
||||
outStream = null;
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
if (outStream != null) {
|
||||
outStream.close();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.load(file.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
throw new ExportException("Error extracting library: " + sourceFileName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
NativeLoader() {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user