Author: desruisseaux
Date: Sat Oct 7 12:51:00 2017
New Revision: 1811420
URL: http://svn.apache.org/viewvc?rev=1811420&view=rev
Log:
Store native libraries in a "linux", "darwin" or "windows" sub-directory at the
same level than the SIS JAR file.
Added:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/darwin/
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/darwin/content.txt
(with props)
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/linux/
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/linux/content.txt
(with props)
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/windows/
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/windows/content.txt
(with props)
Modified:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/README
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Assembler.java
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Filenames.java
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackInput.java
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/unopkg/UnoPkg.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/OS.java
Modified: sis/branches/JDK8/application/sis-console/src/main/artifact/lib/README
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/application/sis-console/src/main/artifact/lib/README?rev=1811420&r1=1811419&r2=1811420&view=diff
==============================================================================
--- sis/branches/JDK8/application/sis-console/src/main/artifact/lib/README
[UTF-8] (original)
+++ sis/branches/JDK8/application/sis-console/src/main/artifact/lib/README
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -1,4 +1,12 @@
This directory contains the sis.jar file together with optional dependencies.
Recognized optional dependencies are:
+ - Derby database
- UCAR netCDF library
+ - ESRI Geometry API
+ - Java Topology Suite
+
+The "linux", "darwin" and "windows" sub-directories contain bridges to Proj.4
+and other libraries through Java Native Interfaces (JNI). They do not contain
+the actual libraries however; Apache SIS uses the libraries installed on host
+computer by packages manager, if any. Those libraries are optional.
Added:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/darwin/content.txt
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/application/sis-console/src/main/artifact/lib/darwin/content.txt?rev=1811420&view=auto
==============================================================================
---
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/darwin/content.txt
(added)
+++
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/darwin/content.txt
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -0,0 +1,2 @@
+Placeholder for MacOS "*.so" files to be copied by the
+org.apache.sis.core:sis-build-helper:dist Maven plugin.
Propchange:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/darwin/content.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/darwin/content.txt
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Added:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/linux/content.txt
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/application/sis-console/src/main/artifact/lib/linux/content.txt?rev=1811420&view=auto
==============================================================================
---
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/linux/content.txt
(added)
+++
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/linux/content.txt
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -0,0 +1,2 @@
+Placeholder for Linux "*.so" files to be copied by the
+org.apache.sis.core:sis-build-helper:dist Maven plugin.
Propchange:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/linux/content.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/linux/content.txt
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Added:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/windows/content.txt
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/application/sis-console/src/main/artifact/lib/windows/content.txt?rev=1811420&view=auto
==============================================================================
---
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/windows/content.txt
(added)
+++
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/windows/content.txt
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -0,0 +1,2 @@
+Placeholder for Windows "*.dll" files to be copied by the
+org.apache.sis.core:sis-build-helper:dist Maven plugin.
Propchange:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/windows/content.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK8/application/sis-console/src/main/artifact/lib/windows/content.txt
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified:
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Assembler.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Assembler.java?rev=1811420&r1=1811419&r2=1811420&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Assembler.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Assembler.java
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -21,6 +21,8 @@ import java.io.IOException;
import java.io.FilenameFilter;
import java.io.FileInputStream;
import java.io.FilterOutputStream;
+import java.util.LinkedHashMap;
+import java.util.Map;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
@@ -37,7 +39,7 @@ import static org.apache.sis.internal.ma
/**
* Creates a ZIP files containing the content of the
<code>application/sis-console/src/main/artifact</code>
* directory together with the Pack200 file created by
<code>BundleCreator</code>.
- * This mojo can be invoked from the command line in the {@code sis-console}
module as below:
+ * This MOJO can be invoked from the command line in the {@code sis-console}
module as below:
*
* <blockquote><code>mvn package
org.apache.sis.core:sis-build-helper:dist</code></blockquote>
*
@@ -52,7 +54,7 @@ import static org.apache.sis.internal.ma
* @since 0.4
* @module
*/
-@Mojo(name = "dist", defaultPhase = LifecyclePhase.INSTALL,
requiresDependencyResolution = ResolutionScope.COMPILE)
+@Mojo(name = "dist", defaultPhase = LifecyclePhase.INSTALL,
requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
public final class Assembler extends AbstractMojo implements FilenameFilter {
/**
* Project information (name, version, URL).
@@ -94,6 +96,7 @@ public final class Assembler extends Abs
final File targetDirectory = new File(rootDirectory, TARGET_DIRECTORY);
final String version = project.getVersion();
final String artifactBase = FINALNAME_PREFIX + version;
+ final Map<String,byte[]> nativeFiles = new LinkedHashMap<>();
try {
final File targetFile = new
File(distributionDirectory(targetDirectory), artifactBase + ".zip");
try (ZipArchiveOutputStream zip = new
ZipArchiveOutputStream(targetFile)) {
@@ -104,20 +107,28 @@ public final class Assembler extends Abs
* have been zipped. Now generate the Pack200 file and zip it
directly (without creating
* a temporary "sis.pack.gz" file).
*/
- final Packer packer = new Packer(project.getName(), version,
BundleCreator.files(project), targetDirectory);
- final ZipArchiveEntry entry = new ZipArchiveEntry(
- artifactBase + '/' + LIB_DIRECTORY + '/' + FATJAR_FILE
+ PACK_EXTENSION);
+ final Packer packer = new Packer(project.getName(), version,
BundleCreator.files(project), targetDirectory, nativeFiles);
+ ZipArchiveEntry entry = new ZipArchiveEntry(artifactBase + '/'
+ LIB_DIRECTORY + '/' + FATJAR_FILE + PACK_EXTENSION);
entry.setMethod(ZipArchiveEntry.STORED);
zip.putArchiveEntry(entry);
packer.preparePack200(FATJAR_FILE + ".jar").pack(new
FilterOutputStream(zip) {
- /*
- * Closes the archive entry, not the ZIP file.
- */
- @Override
- public void close() throws IOException {
+ /** Closes the archive entry, not the ZIP file. */
+ @Override public void close() throws IOException {
zip.closeArchiveEntry();
}
});
+ /*
+ * At this point we finished creating all entries in the ZIP
file, except native resources.
+ * Copy them now.
+ */
+ for (final Map.Entry<String,byte[]> nf :
nativeFiles.entrySet()) {
+ entry = new ZipArchiveEntry(artifactBase + '/' +
LIB_DIRECTORY + '/' + nf.getKey());
+ entry.setUnixMode(0555); // Readable and executable
for all, but not writable.
+ zip.putArchiveEntry(entry);
+ zip.write(nf.getValue());
+ zip.closeArchiveEntry();
+ nf.setValue(null);
+ }
}
} catch (IOException e) {
throw new MojoExecutionException(e.getLocalizedMessage(), e);
@@ -143,6 +154,7 @@ public final class Assembler extends Abs
out.putArchiveEntry(entry);
if (!entry.isDirectory()) {
try (FileInputStream in = new FileInputStream(file)) {
+ // TODO: use InputStream.transferTo(OutputStream) with JDK9.
int n;
while ((n = in.read(buffer)) >= 0) {
out.write(buffer, 0, n);
@@ -166,6 +178,6 @@ public final class Assembler extends Abs
*/
@Override
public boolean accept(final File directory, final String filename) {
- return !filename.isEmpty() && filename.charAt(0) != '.';
+ return !filename.isEmpty() && filename.charAt(0) != '.' &&
!filename.equals(CONTENT_FILE);
}
}
Modified:
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java?rev=1811420&r1=1811419&r2=1811420&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -85,7 +85,7 @@ public final class BundleCreator extends
}
final String version = project.getVersion();
try {
- final Packer packer = new Packer(project.getName(), version,
files(project), targetDirectory);
+ final Packer packer = new Packer(project.getName(), version,
files(project), targetDirectory, null);
packer.preparePack200(FINALNAME_PREFIX + version + ".jar").pack();
} catch (IOException e) {
throw new MojoExecutionException(e.getLocalizedMessage(), e);
Modified:
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Filenames.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Filenames.java?rev=1811420&r1=1811419&r2=1811420&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Filenames.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Filenames.java
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -48,7 +48,8 @@ final class Filenames {
/**
* The name of the file inside {@value #BINARIES_DIRECTORY} where to list
SIS JAR files and their
- * dependencies on platforms that do not support hard links.
+ * dependencies on platforms that do not support hard links. Also the file
to ignore when copying
+ * entries in a ZIP file.
*/
static final String CONTENT_FILE = "content.txt";
Modified:
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackInput.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackInput.java?rev=1811420&r1=1811419&r2=1811420&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackInput.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackInput.java
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -16,6 +16,7 @@
*/
package org.apache.sis.internal.maven;
+import java.util.Map;
import java.util.Enumeration;
import java.util.jar.*;
import java.io.File;
@@ -29,7 +30,7 @@ import java.io.InputStream;
* Those files will be open in read-only mode.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.3
+ * @version 0.8
* @since 0.3
* @module
*/
@@ -51,6 +52,12 @@ final class PackInput implements Closeab
static final String SERVICES = META_INF + "services/";
/**
+ * The prefix of native resources in JAR files. All those resources will
be excluded from
+ * the PACK200 file and stored in {@link #nativeFiles} instead (unless the
map is null).
+ */
+ private static final String NATIVE = "native/";
+
+ /**
* The attribute name in {@code MANIFEST.MF} files for splash screen.
*/
static final Attributes.Name SPLASH_SCREEN = new
Attributes.Name("SplashScreen-Image");
@@ -63,12 +70,19 @@ final class PackInput implements Closeab
/**
* The main class obtained from the manifest, or {@code null} if none.
*/
- public final String mainClass;
+ final String mainClass;
/**
* The splash screen image obtained from the manifest, or {@code null} if
none.
*/
- public final String splashScreen;
+ final String splashScreen;
+
+ /**
+ * The map where to store native files found during iteration over the JAR
entries.
+ * Keys are filename without the {@value #NATIVE} prefix. Values are the
actual data.
+ * If null, then no native files filtering is done.
+ */
+ private final Map<String,byte[]> nativeFiles;
/**
* An enumeration over the entries. We are going to iterate only once.
@@ -83,10 +97,12 @@ final class PackInput implements Closeab
/**
* Opens the given JAR file in read-only mode.
*
- * @param file the file to open.
+ * @param file the file to open.
+ * @param nativeFiles if non-null, where to store native files found
during iteration over the JAR entries.
* @throws IOException if the file can't be open.
*/
- PackInput(final File file) throws IOException {
+ PackInput(final File file, final Map<String,byte[]> nativeFiles) throws
IOException {
+ this.nativeFiles = nativeFiles;
this.file = new JarFile(file);
final Manifest manifest = this.file.getManifest();
if (manifest != null) {
@@ -106,7 +122,7 @@ final class PackInput implements Closeab
*
* @return the next entry, or {@code null} if the iteration is finished.
*/
- JarEntry nextEntry() {
+ JarEntry nextEntry() throws IOException {
if (entries == null) {
entries = file.entries();
}
@@ -118,6 +134,14 @@ final class PackInput implements Closeab
continue;
}
}
+ if (nativeFiles != null && name.startsWith(NATIVE)) {
+ if (!entry.isDirectory()) {
+ if (nativeFiles.put(name.substring(NATIVE.length()),
load()) != null) {
+ throw new IOException("Duplicated entry: " + name);
+ }
+ }
+ continue;
+ }
entry.setMethod(JarEntry.DEFLATED);
entry.setCompressedSize(-1); // Change in
method has changed the compression size.
return entry;
@@ -138,6 +162,26 @@ final class PackInput implements Closeab
}
/**
+ * Loads in memory the content of current JAR entry.
+ * This method should be invoked only for entries of reasonable size.
+ */
+ private byte[] load() throws IOException {
+ final long size = entry.getSize();
+ if (size <= 0 || size > Integer.MAX_VALUE) {
+ throw new IOException("Unsupported size for \"" + entry.getName()
+ "\": " + size);
+ }
+ final byte[] content = new byte[(int) size];
+ final int actual;
+ try (InputStream in = getInputStream()) {
+ actual = in.read(content);
+ }
+ if (actual != size) {
+ throw new IOException("Expected " + size + " bytes in \"" +
entry.getName() + "\" but found " + actual);
+ }
+ return content;
+ }
+
+ /**
* Returns the input stream for the current entry.
*
* @param entry The entry for which to get an input stream.
Modified:
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java?rev=1811420&r1=1811419&r2=1811420&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -215,7 +215,7 @@ final class PackOutput implements Closea
final byte[] buffer = new byte[64 * 1024];
for (final Iterator<Map.Entry<File,PackInput>> it =
inputJARs.entrySet().iterator(); it.hasNext();) {
final Map.Entry<File,PackInput> inputJAR = it.next();
- it.remove(); // Needs to be removed before the inner loop below.
+ it.remove(); // Needs to be
removed before the inner loop below.
try (PackInput input = inputJAR.getValue()) {
for (JarEntry entry; (entry = input.nextEntry()) != null;) {
final String name = entry.getName();
@@ -253,7 +253,7 @@ final class PackOutput implements Closea
* @param buffer temporary buffer to reuse at each method call.
* @throws IOException if an error occurred during the copy.
*/
- void copy(final InputStream in, final byte[] buffer) throws IOException {
+ private void copy(final InputStream in, final byte[] buffer) throws
IOException {
int n;
while ((n = in.read(buffer)) >= 0) {
outputStream.write(buffer, 0, n);
Modified:
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java?rev=1811420&r1=1811419&r2=1811420&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -53,18 +53,29 @@ final class Packer {
private final File targetDirectory;
/**
+ * The map where to store native files found during iteration over the JAR
entries.
+ * Keys are filename without the {@value #NATIVE} prefix. Values are the
actual data.
+ * If null, then no native files filtering is done.
+ */
+ private final Map<String,byte[]> nativeFiles;
+
+ /**
* Creates a packer.
*
* @param projectName the project name to declare in the manifest
file, or {@code null} if none.
* @param version the project version to declare in the manifest
file, or {@code null} if none.
* @param files the JAR files of the main project together
with its dependencies.
* @param targetDirectory the Maven target directory.
+ * @param nativeFiles if non-null, where to store native files found
during iteration over the JAR entries.
*/
- Packer(final String projectName, final String version, final Set<File>
files, final File targetDirectory) {
+ Packer(final String projectName, final String version, final Set<File>
files, final File targetDirectory,
+ final Map<String,byte[]> nativeFiles)
+ {
this.projectName = projectName;
this.version = version;
this.files = files;
this.targetDirectory = targetDirectory;
+ this.nativeFiles = nativeFiles;
}
/**
@@ -77,7 +88,7 @@ final class Packer {
if (!file.isFile() || !file.canRead()) {
throw new IllegalArgumentException("Not a file or can not
read: " + file);
}
- if (inputJARs.put(file, new PackInput(file)) != null) {
+ if (inputJARs.put(file, new PackInput(file, nativeFiles)) != null)
{
throw new IllegalArgumentException("Duplicated JAR: " + file);
}
}
Modified:
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/unopkg/UnoPkg.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/unopkg/UnoPkg.java?rev=1811420&r1=1811419&r2=1811420&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/unopkg/UnoPkg.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-build-helper/src/main/java/org/apache/sis/internal/unopkg/UnoPkg.java
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -44,7 +44,7 @@ import static java.util.jar.Pack200.Pack
* @since 0.8
* @module
*/
-@Mojo(name = "unopkg", defaultPhase = LifecyclePhase.PACKAGE,
requiresDependencyResolution = ResolutionScope.COMPILE)
+@Mojo(name = "unopkg", defaultPhase = LifecyclePhase.PACKAGE,
requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
public final class UnoPkg extends AbstractMojo implements FilenameFilter {
/**
* The subdirectory (relative to {@link #baseDirectory}) where the UNO
files are expected.
Modified:
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/OS.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/OS.java?rev=1811420&r1=1811419&r2=1811420&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/OS.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/OS.java
[UTF-8] Sat Oct 7 12:51:00 2017
@@ -17,6 +17,7 @@
package org.apache.sis.internal.system;
import java.net.URL;
+import java.net.URI;
import java.net.URISyntaxException;
import java.io.File;
import java.io.InputStream;
@@ -122,7 +123,7 @@ public enum OS {
*/
public static void load(final Class<?> caller, final String name) {
try {
- System.load(current().nativeLibrary(caller.getClassLoader(),
name));
+ System.load(current().nativeLibrary(caller, name));
} catch (IOException | SecurityException e) {
throw (UnsatisfiedLinkError) new
UnsatisfiedLinkError(e.getMessage()).initCause(e);
}
@@ -133,7 +134,7 @@ public enum OS {
* If the resources can not be accessed by an absolute path, then this
method
* copies the resource in a temporary file.
*
- * @param loader the loader of the JAR file where to look for native
resources.
+ * @param caller a class in the JAR file where to look for native
resources.
* @param name the native library name without {@code ".so"} or {@code
".dll"} extension.
* @return absolute path to the library (may be a temporary file).
* @throws IOException if an error occurred while copying the library to a
temporary file.
@@ -142,11 +143,40 @@ public enum OS {
*
* @see System#load(String)
*/
- private String nativeLibrary(final ClassLoader loader, final String name)
throws IOException {
+ private String nativeLibrary(final Class<?> caller, final String name)
throws IOException {
if (libdir != null) {
final String ext = unix ? ".so" : ".dll";
- final String path = "native/" + libdir + '/' + name + ext;
- final URL res = loader.getResource(path);
+ final String path = libdir + '/' + name + ext;
+ final ClassLoader loader = caller.getClassLoader();
+ /*
+ * First, verify if the "linux", "darwin" or "windows" directory
exists at the same level
+ * than the JAR file containing the caller class. If it exists,
then we will use it. This
+ * check avoid the need to copy the ".so" or ".dll" file in a
temporary location. If the
+ * directory does not exist, then we do NOT create it in order to
reduce the risk to mess
+ * with user's installation.
+ *
+ * Example of URL for a JAR entry:
jar:file:/home/…/sis-gdal.jar!/org/apache/…/PJ.class
+ */
+ URL res = loader.getResource(caller.getName().replace('.',
'/').concat(".class"));
+ if (res != null && "jar".equals(res.getProtocol())) {
+ String file = res.getPath();
+ final int s = file.indexOf('!');
+ if (s >= 0) try {
+ File location = new File(new URI(file.substring(0, s)));
+ location = new File(location.getParentFile(), path);
+ if (location.canExecute()) {
+ return location.getAbsolutePath();
+ }
+ } catch (IllegalArgumentException | URISyntaxException e) {
+
Logging.recoverableException(Logging.getLogger(Loggers.SYSTEM), OS.class,
"nativeLibrary", e);
+ }
+ }
+ /*
+ * If we didn't found an existing "linux", "darwin" or "windows"
directory with native library,
+ * copy the library in a temporary file. That file will be deleted
on JVM exists, so a new file
+ * will be copied each time the application is executed.
+ */
+ res = loader.getResource("native/".concat(path));
if (res != null) {
try {
return new File(res.toURI()).getAbsolutePath();