Skip to content

Commit

Permalink
moved library management out of api
Browse files Browse the repository at this point in the history
  • Loading branch information
olir committed Apr 6, 2018
1 parent a08858c commit 853df02
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 120 deletions.
88 changes: 88 additions & 0 deletions app/src/main/java/de/serviceflow/frankenstein/LibraryManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package de.serviceflow.frankenstein;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class LibraryManager {

private static final String TEMPPATH = LibraryManager.class.getPackage().getName();
private static final Set<String> loadedLibraries = Collections.synchronizedSet(new HashSet<String>());

public String prepareLoadLibrary(Class<?> invokerClass, String libraryBasename) throws UnsatisfiedLinkError {
System.out.println("sun.arch.data.model=" + System.getProperty("sun.arch.data.model"));
System.out.println("os.arch=" + System.getProperty("os.arch"));


String plattformLibraryName = libraryBasename;
String suffix = ".dll";
if (System.getProperty("os.arch").contains("64") && System.getProperty("sun.arch.data.model").contains("64")) {
// load 64-bit lib
plattformLibraryName = plattformLibraryName + "-win64";
} else {
// load 32-bit lib
plattformLibraryName = plattformLibraryName + "-win32";
}
// TODO !!! ...

prepareLoadLibraryImpl(invokerClass, plattformLibraryName, suffix);

return plattformLibraryName;
}

private static void prepareLoadLibraryImpl(Class<?> invokerClass, String plattformLibraryName, String suffix)
throws UnsatisfiedLinkError {
synchronized (loadedLibraries) {

if (loadedLibraries.contains(plattformLibraryName.intern()))
return;

String libFileName = plattformLibraryName + suffix;
String location = "/" + libFileName;
InputStream binary = invokerClass.getResourceAsStream("/" + libFileName);
if (binary == null)
throw new Error("binary not found: " + "/" + libFileName);

try {
Path tmpDir = Files.createTempDirectory(TEMPPATH);
tmpDir.toFile().deleteOnExit();
Path destination = tmpDir.resolve("./" + location).normalize();

try {
Files.createDirectories(destination.getParent());
Files.copy(binary, destination);
String nPath = destination.getParent().normalize().toString();

Field field = ClassLoader.class.getDeclaredField("usr_paths");
field.setAccessible(true);

Set<String> myPath = new HashSet<String>(Arrays.asList((String[]) field.get(null)));
myPath.add(nPath);

field.set(null, myPath.toArray(new String[myPath.size()]));

System.setProperty("java.library.path",
System.getProperty("java.library.path") + File.pathSeparator + nPath);
} catch (IllegalAccessException x) {
throw new Error("IllegalAccessException!?", x);
} catch (NoSuchFieldException x) {
throw new Error("NoSuchFieldException!?", x);
}

loadedLibraries.add(plattformLibraryName.intern());

} catch (final IOException x) {
throw new Error("Error writing native library", x);
}
// }
}
}

}
4 changes: 2 additions & 2 deletions app/src/main/resources/plugin.set
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
../../../../plugin-opencv/target
../../../../plugin-jogamp/target
../../../../plugin-opencv/distribution/target
../../../../plugin-jogamp/distribution/target
Original file line number Diff line number Diff line change
@@ -1,118 +1,41 @@
package de.serviceflow.frankenstein.plugin.api;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public abstract class NativeFilter {
// private static boolean loaderCalled = false;
// private static UnsatisfiedLinkError error = null;
private static final Set<String> loadedLibraries = Collections.synchronizedSet(new HashSet<String>());

public static void prepareLoadLibrary(NativeFilter invoker) throws UnsatisfiedLinkError {
// if (!loaderCalled) {
// loaderCalled = true;
System.out.println("Working Directory = " + new File(".").getAbsolutePath());
try {
String packageName = invoker.getClass().getPackage().getName();
String pluginName = packageName.substring(packageName.lastIndexOf(".plugin.")+1);
pluginName = pluginName.substring(0, pluginName.indexOf('.', pluginName.indexOf('.')+1)).replace('.', '-');
if (System.getProperty("os.arch").contains("64")
&& System.getProperty("sun.arch.data.model").contains("64")) {
// load 64-bit lib
prepareLoadLibrary(invoker, pluginName+"-64");
} else {
// load 32-bit lib
prepareLoadLibrary(invoker, pluginName+"-32");
}
} catch (UnsatisfiedLinkError t) {
System.out.println("sun.arch.data.model=" + System.getProperty("sun.arch.data.model"));
System.out.println("os.arch=" + System.getProperty("os.arch"));

// error = t;
throw t;
}
// if (error != null)
// throw error; // throw again
// }
}

private static void prepareLoadLibrary(NativeFilter invoker, String libraryName) throws UnsatisfiedLinkError {
synchronized (loadedLibraries) {

if (loadedLibraries.contains(libraryName.intern()))
return;

try {
invoker.loadLibrary(libraryName);
} catch (final UnsatisfiedLinkError e) {
if (!String.format("no %s in java.library.path", libraryName).equals(e.getMessage())) {
System.out.println(
"!!! [1] UnsatisfiedLinkError @ libraryName='" + libraryName + " message: "+e.getMessage()+", but lookup seems to successful. java.library.path="+System.getProperty("java.library.path"));
throw e;
}

String libFileName = libraryName + ".dll";
String location = "/" + libFileName;
InputStream binary = invoker.getClass().getResourceAsStream("/" + libFileName);
if (binary == null)
throw new Error("binary not found: " + "/" + libFileName);


try {
Path tmpDir = Files.createTempDirectory("frankenstein");
tmpDir.toFile().deleteOnExit();
Path destination = tmpDir.resolve("./" + location).normalize();

try {
Files.createDirectories(destination.getParent());
Files.copy(binary, destination);
String nPath = destination.getParent().normalize().toString();

Field field = ClassLoader.class.getDeclaredField("usr_paths");
field.setAccessible(true);

Set<String> myPath = new HashSet<String>(Arrays.asList((String[]) field.get(null)));
myPath.add(nPath);

field.set(null, myPath.toArray(new String[myPath.size()]));

System.setProperty("java.library.path",
System.getProperty("java.library.path") + File.pathSeparator + nPath);
} catch (IllegalAccessException x) {
throw new Error("IllegalAccessException!?", x);
} catch (NoSuchFieldException x) {
throw new Error("NoSuchFieldException!?", x);
}

try {
invoker.loadLibrary(libraryName);
} catch (UnsatisfiedLinkError x) {
System.out.println("!!! [1] UnsatisfiedLinkError: "+e.getMessage()+". But found binary in classpath -> Relocated to "+destination);
System.out.println(
"!!! [2] UnsatisfiedLinkError @ libraryName='" + libraryName + " message: "+x.getMessage());
throw x;
}

loadedLibraries.add(libraryName.intern());

} catch (final IOException x) {
throw new Error("Error writing native library", x);
}
}
}
}

protected NativeFilter() throws UnsatisfiedLinkError {
prepareLoadLibrary(this);
}

protected abstract void loadLibrary(String name);
protected NativeFilter() throws UnsatisfiedLinkError {
prepareLoadLibrary(this);
}

private void prepareLoadLibrary(NativeFilter invoker) throws UnsatisfiedLinkError {
String packageName = invoker.getClass().getPackage().getName();
String pluginName = packageName.substring(packageName.lastIndexOf(".plugin.") + 1);
pluginName = pluginName.substring(0, pluginName.indexOf('.', pluginName.indexOf('.') + 1)).replace('.', '-');

invoker.loadLibrary(prepareLoadLibrary(invoker.getClass(), pluginName));
}

private String prepareLoadLibrary(Class<?> invokerClass, String name) throws UnsatisfiedLinkError {
try {
Class<?> c = invokerClass.getClassLoader().loadClass("de.serviceflow.frankenstein.LibraryManager");
Object o = c.newInstance();
Method m = c.getMethod("prepareLoadLibrary", Class.class, String.class);
return (String) m.invoke(o, invokerClass, name);
} catch (SecurityException | ClassNotFoundException | NoSuchMethodException | InstantiationException
| IllegalAccessException | IllegalArgumentException e) {
e.printStackTrace();
throw new UnsatisfiedLinkError("Prepare to load library failed for " + name + " with " + invokerClass.getName());
}
catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t!=null)
t.printStackTrace();
e.printStackTrace();
throw new UnsatisfiedLinkError("Prepare to load library failed for " + name + " with " + invokerClass.getName());
}
}

protected abstract void loadLibrary(String name);
}
4 changes: 2 additions & 2 deletions plugin-jogamp/distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</dependency>
<dependency>
<groupId>de.serviceflow.frankenstein.plugin.jogamp</groupId>
<artifactId>plugin-jogamp-64</artifactId>
<artifactId>plugin-jogamp-win64</artifactId>
<version>0.3.4-SNAPSHOT</version>
<type>dll</type>
</dependency>
Expand All @@ -48,7 +48,7 @@
<configuration>
<tasks>
<unzip src="${project.basedir}/../java/target/plugin-jogamp-${project.version}.jar" dest="${project.build.directory}/assembly"/>
<copy file="${project.basedir}/../native/win64/target/plugin-jogamp-64.dll" tofile="${project.build.directory}/assembly/plugin-jogamp-64.dll"/>
<copy file="${project.basedir}/../native/win64/target/plugin-jogamp-win64.dll" tofile="${project.build.directory}/assembly/plugin-jogamp-win64.dll"/>
<jar destfile="${project.build.directory}/plugin-jogamp-${project.version}.jar" basedir="${project.build.directory}/assembly" manifest="${project.build.directory}/assembly/META-INF/MANIFEST.MF"/>
<copy file="${project.basedir}/../java/target/plugin-jogamp-${project.version}-sources.jar" tofile="${project.build.directory}/plugin-jogamp-${project.version}-sources.jar"/>
<copy file="${project.basedir}/../java/target/plugin-jogamp-${project.version}-javadoc.jar" tofile="${project.build.directory}/plugin-jogamp-${project.version}-javadoc.jar"/>
Expand Down
2 changes: 1 addition & 1 deletion plugin-jogamp/native/win64/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</parent>

<groupId>de.serviceflow.frankenstein.plugin.jogamp</groupId>
<artifactId>plugin-jogamp-64</artifactId>
<artifactId>plugin-jogamp-win64</artifactId>
<version>0.3.4-SNAPSHOT</version>
<packaging>dll</packaging>

Expand Down
4 changes: 2 additions & 2 deletions plugin-opencv/distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</dependency>
<dependency>
<groupId>de.serviceflow.frankenstein.plugin.opencv</groupId>
<artifactId>plugin-opencv-64</artifactId>
<artifactId>plugin-opencv-win64</artifactId>
<version>0.3.4-SNAPSHOT</version>
<type>dll</type>
</dependency>
Expand All @@ -48,7 +48,7 @@
<configuration>
<tasks>
<unzip src="${project.basedir}/../java/target/plugin-opencv-${project.version}.jar" dest="${project.build.directory}/assembly"/>
<copy file="${project.basedir}/../native/win64/target/plugin-opencv-64.dll" tofile="${project.build.directory}/assembly/plugin-opencv-64.dll"/>
<copy file="${project.basedir}/../native/win64/target/plugin-opencv-win64.dll" tofile="${project.build.directory}/assembly/plugin-opencv-win64.dll"/>
<jar destfile="${project.build.directory}/plugin-opencv-${project.version}.jar" basedir="${project.build.directory}/assembly" manifest="${project.build.directory}/assembly/META-INF/MANIFEST.MF"/>
<copy file="${project.basedir}/../java/target/plugin-opencv-${project.version}-sources.jar" tofile="${project.build.directory}/plugin-opencv-${project.version}-sources.jar"/>
<copy file="${project.basedir}/../java/target/plugin-opencv-${project.version}-javadoc.jar" tofile="${project.build.directory}/plugin-opencv-${project.version}-javadoc.jar"/>
Expand Down
2 changes: 1 addition & 1 deletion plugin-opencv/native/win64/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</parent>

<groupId>de.serviceflow.frankenstein.plugin.opencv</groupId>
<artifactId>plugin-opencv-64</artifactId>
<artifactId>plugin-opencv-win64</artifactId>
<version>0.3.4-SNAPSHOT</version>
<packaging>dll</packaging>

Expand Down

0 comments on commit 853df02

Please sign in to comment.