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();


Reply via email to