Extend to load binaries as well
This commit is contained in:
@@ -7,7 +7,7 @@ task wrapper(type: Wrapper) {
|
||||
|
||||
group = 'com.github.boukefalos'
|
||||
archivesBaseName = 'jlibloader'
|
||||
version = '0.2'
|
||||
version = '0.3'
|
||||
|
||||
uploadArchives {
|
||||
repositories.mavenDeployer {
|
||||
|
||||
@@ -1,29 +1,17 @@
|
||||
/*
|
||||
* Copyright 2012 Adam Murdoch
|
||||
*
|
||||
* 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 com.github.boukefalos.jlibloader;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.github.boukefalos.jlibloader.internal.NativeBinaryLoader;
|
||||
import com.github.boukefalos.jlibloader.internal.NativeBinaryLocator;
|
||||
import com.github.boukefalos.jlibloader.internal.NativeLibraryLoader;
|
||||
import com.github.boukefalos.jlibloader.internal.NativeLibraryLocator;
|
||||
import com.github.boukefalos.jlibloader.internal.Platform;
|
||||
|
||||
public class Native {
|
||||
private static NativeLibraryLoader loader;
|
||||
private static Platform platform;
|
||||
private static NativeLibraryLoader libraryLoader;
|
||||
private static NativeBinaryLoader binaryLoader;
|
||||
|
||||
private Native() {
|
||||
}
|
||||
@@ -37,12 +25,13 @@ public class Native {
|
||||
* @throws NativeLibraryUnavailableException When the native library is not available on the current machine.
|
||||
* @throws NativeException On failure to load the native library.
|
||||
*/
|
||||
static public void init(File extractDir) throws NativeLibraryUnavailableException, NativeException {
|
||||
static public void init(File extractDir) throws NativeException {
|
||||
synchronized (Native.class) {
|
||||
if (loader == null) {
|
||||
Platform platform = Platform.current();
|
||||
if (platform == null) {
|
||||
platform = Platform.current();
|
||||
try {
|
||||
loader = new NativeLibraryLoader(platform, new NativeLibraryLocator(extractDir));
|
||||
libraryLoader = new NativeLibraryLoader(platform, new NativeLibraryLocator(extractDir));
|
||||
binaryLoader = new NativeBinaryLoader(platform, new NativeBinaryLocator(extractDir));
|
||||
} catch (NativeException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
@@ -59,12 +48,26 @@ public class Native {
|
||||
public static void load(String group, String name, String file) {
|
||||
init(null);
|
||||
try {
|
||||
loader.load(group, name, Platform.current().getLibraryName(file));
|
||||
libraryLoader.load(group, name, Platform.current().getLibraryName(file));
|
||||
} catch (NativeException e) {
|
||||
throw e;
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new NativeException("Failed to load native library.");
|
||||
}
|
||||
|
||||
throw new NativeException("Failed to load native library.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void binary(String group, String name) {
|
||||
binary(group, name, name);
|
||||
}
|
||||
|
||||
public static String binary(String group, String name, String file) {
|
||||
init(null);
|
||||
try {
|
||||
return binaryLoader.load(group, name, Platform.current().getBinaryName(file));
|
||||
} catch (NativeException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new NativeException("Failed to load native binary.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.github.boukefalos.jlibloader;
|
||||
|
||||
/**
|
||||
* Thrown when a given integration is not available for the current machine.
|
||||
*/
|
||||
public class NativeBinaryUnavailableException extends NativeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NativeBinaryUnavailableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2012 Adam Murdoch
|
||||
*
|
||||
* 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 com.github.boukefalos.jlibloader;
|
||||
|
||||
public class NativeException extends RuntimeException {
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2012 Adam Murdoch
|
||||
*
|
||||
* 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 com.github.boukefalos.jlibloader;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.github.boukefalos.jlibloader.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.github.boukefalos.jlibloader.NativeBinaryUnavailableException;
|
||||
import com.github.boukefalos.jlibloader.NativeException;
|
||||
|
||||
public class NativeBinaryLoader extends NativeLoader {
|
||||
private HashMap<String,String> binaryFileMap = new HashMap<String,String>();
|
||||
private NativeBinaryLocator nativeBinaryLocator;
|
||||
|
||||
public NativeBinaryLoader(Platform platform, NativeBinaryLocator nativeBinaryLocator) {
|
||||
this.platform = platform;
|
||||
this.nativeBinaryLocator = nativeBinaryLocator;
|
||||
}
|
||||
|
||||
public String load(String binaryGroupName, String binaryName, String binaryFileName) {
|
||||
if (binaryFileMap.containsKey(binaryFileName)) {
|
||||
return binaryFileMap.get(binaryFileName);
|
||||
}
|
||||
try {
|
||||
File binFile = nativeBinaryLocator.find(new NativeDef(binaryGroupName, binaryName, binaryFileName, platform.getId()));
|
||||
if (binFile == null) {
|
||||
throw new NativeBinaryUnavailableException(String.format("Native binary '%s' is not available for %s.", binaryFileName, platform));
|
||||
}
|
||||
String binaryPath = binFile.getAbsolutePath();
|
||||
binaryFileMap.put(binaryFileName, binaryPath);
|
||||
return binaryPath;
|
||||
} catch (NativeException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
throw new NativeException(String.format("Failed to load native library '%s' for %s.", binaryFileName, platform), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.github.boukefalos.jlibloader.internal;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class NativeBinaryLocator extends NativeLocator {
|
||||
public NativeBinaryLocator(File extractDir) {
|
||||
super(extractDir);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.github.boukefalos.jlibloader.internal;
|
||||
|
||||
public class LibraryDef {
|
||||
public class NativeDef {
|
||||
final String group;
|
||||
final String name;
|
||||
final String file;
|
||||
final String platform;
|
||||
|
||||
public LibraryDef(String group, String name, String file, String platform) {
|
||||
public NativeDef(String group, String name, String file, String platform) {
|
||||
this.group = group;
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
@@ -21,7 +21,7 @@ public class LibraryDef {
|
||||
if (obj == null || obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
LibraryDef other = (LibraryDef) obj;
|
||||
NativeDef other = (NativeDef) obj;
|
||||
return name.equals(other.name) && platform.equals(other.platform);
|
||||
}
|
||||
|
||||
@@ -33,4 +33,4 @@ public class LibraryDef {
|
||||
public String getGroupPath() {
|
||||
return group.replace(".", "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2012 Adam Murdoch
|
||||
*
|
||||
* 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 com.github.boukefalos.jlibloader.internal;
|
||||
|
||||
import java.io.File;
|
||||
@@ -23,9 +7,8 @@ import java.util.Set;
|
||||
import com.github.boukefalos.jlibloader.NativeException;
|
||||
import com.github.boukefalos.jlibloader.NativeLibraryUnavailableException;
|
||||
|
||||
public class NativeLibraryLoader {
|
||||
private final Set<String> loaded = new HashSet<String>();
|
||||
private final Platform platform;
|
||||
public class NativeLibraryLoader extends NativeLoader {
|
||||
private final Set<String> loaded = new HashSet<String>();
|
||||
private final NativeLibraryLocator nativeLibraryLocator;
|
||||
|
||||
public NativeLibraryLoader(Platform platform, NativeLibraryLocator nativeLibraryLocator) {
|
||||
@@ -38,7 +21,7 @@ public class NativeLibraryLoader {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
File libFile = nativeLibraryLocator.find(new LibraryDef(libraryGroupName, libraryName, libraryFileName, platform.getId()));
|
||||
File libFile = nativeLibraryLocator.find(new NativeDef(libraryGroupName, libraryName, libraryFileName, platform.getId()));
|
||||
if (libFile == null) {
|
||||
throw new NativeLibraryUnavailableException(String.format("Native library '%s' is not available for %s.", libraryFileName, platform));
|
||||
}
|
||||
@@ -51,4 +34,4 @@ public class NativeLibraryLoader {
|
||||
}
|
||||
loaded.add(libraryFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,118 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012 Adam Murdoch
|
||||
*
|
||||
* 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 com.github.boukefalos.jlibloader.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.URL;
|
||||
|
||||
import com.github.boukefalos.jlibloader.NativeException;
|
||||
|
||||
public class NativeLibraryLocator {
|
||||
private final File extractDir;
|
||||
|
||||
public class NativeLibraryLocator extends NativeLocator {
|
||||
public NativeLibraryLocator(File extractDir) {
|
||||
this.extractDir = extractDir;
|
||||
}
|
||||
super(extractDir);
|
||||
}
|
||||
|
||||
public File find(LibraryDef libraryDef) throws IOException {
|
||||
String resourceName = String.format("%s/%s/%s/%s", libraryDef.getGroupPath(), libraryDef.name, libraryDef.platform, libraryDef.file);
|
||||
if (extractDir != null) {
|
||||
File libFile = new File(extractDir, String.format("%s/%s", libraryDef.platform, libraryDef.file));
|
||||
File lockFile = new File(libFile.getParentFile(), libFile.getName() + ".lock");
|
||||
lockFile.getParentFile().mkdirs();
|
||||
lockFile.createNewFile();
|
||||
RandomAccessFile lockFileAccess = new RandomAccessFile(lockFile, "rw");
|
||||
try {
|
||||
if (lockFile.length() > 0 && lockFileAccess.readBoolean()) {
|
||||
// Library has been extracted
|
||||
return libFile;
|
||||
}
|
||||
URL resource = getClass().getClassLoader().getResource(resourceName);
|
||||
if (resource != null) {
|
||||
// Extract library and write marker to lock file
|
||||
libFile.getParentFile().mkdirs();
|
||||
copy(resource, libFile);
|
||||
lockFileAccess.seek(0);
|
||||
lockFileAccess.writeBoolean(true);
|
||||
return libFile;
|
||||
}
|
||||
} finally {
|
||||
// Also releases lock
|
||||
lockFileAccess.close();
|
||||
}
|
||||
} else {
|
||||
URL resource = getClass().getClassLoader().getResource(resourceName);
|
||||
if (resource != null) {
|
||||
File libFile;
|
||||
File libDir = File.createTempFile(libraryDef.file, "dir");
|
||||
libDir.delete();
|
||||
libDir.mkdirs();
|
||||
libFile = new File(libDir, libraryDef.file);
|
||||
libFile.deleteOnExit();
|
||||
libDir.deleteOnExit();
|
||||
copy(resource, libFile);
|
||||
return libFile;
|
||||
}
|
||||
}
|
||||
|
||||
String componentName = libraryDef.file.replaceFirst("^lib", "").replaceFirst("\\.\\w+$", "");
|
||||
int pos = componentName.indexOf("-");
|
||||
while (pos >= 0) {
|
||||
componentName = componentName.substring(0, pos) + Character.toUpperCase(componentName.charAt(pos + 1)) + componentName.substring(pos + 2);
|
||||
pos = componentName.indexOf("-", pos);
|
||||
}
|
||||
File libFile = new File(String.format("build/binaries/%sSharedLibrary/%s/%s", componentName, libraryDef.platform.replace("-", "_"), libraryDef.file));
|
||||
if (libFile.isFile()) {
|
||||
return libFile;
|
||||
}
|
||||
libFile = new File(String.format("build/binaries/mainSharedLibrary/%s/%s", libraryDef.platform.replace("-", "_"), libraryDef.file));
|
||||
if (libFile.isFile()) {
|
||||
return libFile;
|
||||
}
|
||||
public File find(NativeDef nativeDef) throws IOException {
|
||||
if (super.find(nativeDef) == null) {
|
||||
String componentName = nativeDef.file.replaceFirst("^lib", "").replaceFirst("\\.\\w+$", "");
|
||||
int pos = componentName.indexOf("-");
|
||||
while (pos >= 0) {
|
||||
componentName = componentName.substring(0, pos) + Character.toUpperCase(componentName.charAt(pos + 1)) + componentName.substring(pos + 2);
|
||||
pos = componentName.indexOf("-", pos);
|
||||
}
|
||||
File libFile = new File(String.format("build/binaries/%sSharedLibrary/%s/%s", componentName, nativeDef.platform.replace("-", "_"), nativeDef.file));
|
||||
if (libFile.isFile()) {
|
||||
return libFile;
|
||||
}
|
||||
libFile = new File(String.format("build/binaries/mainSharedLibrary/%s/%s", nativeDef.platform.replace("-", "_"), nativeDef.file));
|
||||
if (libFile.isFile()) {
|
||||
return libFile;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void copy(URL source, File dest) {
|
||||
try {
|
||||
InputStream inputStream = source.openStream();
|
||||
try {
|
||||
OutputStream outputStream = new FileOutputStream(dest);
|
||||
try {
|
||||
byte[] buffer = new byte[4096];
|
||||
while (true) {
|
||||
int nread = inputStream.read(buffer);
|
||||
if (nread < 0) {
|
||||
break;
|
||||
}
|
||||
outputStream.write(buffer, 0, nread);
|
||||
}
|
||||
} finally {
|
||||
outputStream.close();
|
||||
}
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new NativeException(String.format("Could not extract native JNI library."), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.boukefalos.jlibloader.internal;
|
||||
|
||||
public abstract class NativeLoader {
|
||||
protected Platform platform;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.github.boukefalos.jlibloader.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.URL;
|
||||
|
||||
import com.github.boukefalos.jlibloader.NativeException;
|
||||
|
||||
public class NativeLocator {
|
||||
protected final File extractDir;
|
||||
|
||||
public NativeLocator(File extractDir) {
|
||||
this.extractDir = extractDir;
|
||||
}
|
||||
|
||||
public File find(NativeDef nativeDef) throws IOException {
|
||||
String resourceName = String.format("%s/%s/%s/%s", nativeDef.getGroupPath(), nativeDef.name, nativeDef.platform, nativeDef.file);
|
||||
if (extractDir != null) {
|
||||
File libFile = new File(extractDir, String.format("%s/%s", nativeDef.platform, nativeDef.file));
|
||||
File lockFile = new File(libFile.getParentFile(), libFile.getName() + ".lock");
|
||||
lockFile.getParentFile().mkdirs();
|
||||
lockFile.createNewFile();
|
||||
RandomAccessFile lockFileAccess = new RandomAccessFile(lockFile, "rw");
|
||||
try {
|
||||
if (lockFile.length() > 0 && lockFileAccess.readBoolean()) {
|
||||
// Library has been extracted
|
||||
return libFile;
|
||||
}
|
||||
URL resource = getClass().getClassLoader().getResource(resourceName);
|
||||
if (resource != null) {
|
||||
// Extract library and write marker to lock file
|
||||
libFile.getParentFile().mkdirs();
|
||||
copy(resource, libFile);
|
||||
lockFileAccess.seek(0);
|
||||
lockFileAccess.writeBoolean(true);
|
||||
return libFile;
|
||||
}
|
||||
} finally {
|
||||
// Also releases lock
|
||||
lockFileAccess.close();
|
||||
}
|
||||
} else {
|
||||
URL resource = getClass().getClassLoader().getResource(resourceName);
|
||||
if (resource != null) {
|
||||
File libFile;
|
||||
File libDir = File.createTempFile(nativeDef.file, "dir");
|
||||
libDir.delete();
|
||||
libDir.mkdirs();
|
||||
libFile = new File(libDir, nativeDef.file);
|
||||
libFile.deleteOnExit();
|
||||
libDir.deleteOnExit();
|
||||
copy(resource, libFile);
|
||||
return libFile;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static void copy(URL source, File dest) {
|
||||
try {
|
||||
InputStream inputStream = source.openStream();
|
||||
try {
|
||||
OutputStream outputStream = new FileOutputStream(dest);
|
||||
try {
|
||||
byte[] buffer = new byte[4096];
|
||||
while (true) {
|
||||
int nread = inputStream.read(buffer);
|
||||
if (nread < 0) {
|
||||
break;
|
||||
}
|
||||
outputStream.write(buffer, 0, nread);
|
||||
}
|
||||
} finally {
|
||||
outputStream.close();
|
||||
}
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new NativeException(String.format("Could not extract native file."), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.github.boukefalos.jlibloader.internal;
|
||||
|
||||
import com.github.boukefalos.jlibloader.NativeBinaryUnavailableException;
|
||||
import com.github.boukefalos.jlibloader.NativeLibraryUnavailableException;
|
||||
|
||||
public abstract class Platform {
|
||||
@@ -64,7 +65,7 @@ public abstract class Platform {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWindows() {
|
||||
public boolean isWindows() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -77,6 +78,10 @@ public abstract class Platform {
|
||||
throw new NativeLibraryUnavailableException(String.format("Native library is not available for %s.", toString()));
|
||||
}
|
||||
|
||||
public String getBinaryName(String name) {
|
||||
throw new NativeBinaryUnavailableException(String.format("Native binary is not available for %s.", toString()));
|
||||
}
|
||||
|
||||
public abstract String getId();
|
||||
|
||||
private static String getOperatingSystem() {
|
||||
@@ -97,6 +102,11 @@ public abstract class Platform {
|
||||
public String getLibraryName(String name) {
|
||||
return String.format("%s.dll", name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBinaryName(String name) {
|
||||
return String.format("%s.exe", name);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Window32Bit extends Windows {
|
||||
|
||||
Reference in New Issue
Block a user