Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 24 additions & 75 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.release>11</maven.compiler.release>
<xcodeScheme>Debug</xcodeScheme>
</properties>

Expand All @@ -65,7 +64,7 @@
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
Expand All @@ -74,7 +73,7 @@

<organization>
<name>Web Lite Solutions Corp.</name>
<url>http://solutions.weblite.ca</url>
<url>https://solutions.weblite.ca/</url>
</organization>

<issueManagement>
Expand All @@ -91,29 +90,6 @@
<url>https://github.com/shannah/Java-Objective-C-Bridge</url>
</scm>

<repositories>
<repository>
<id>mvnrepository</id>
<name>mvnrepository</name>
<url>https://www.mvnrepository.com</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

<pluginRepositories>
<!-- eclipse lifecycle plugin is only available here -->
<pluginRepository>
<id>mvnrepository</id>
<name>mvnrepository</name>
<url>https://www.mvnrepository.com</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>

<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
Expand All @@ -136,16 +112,16 @@
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.4</version>
<version>3.4.2</version>
</extension>
</extensions>
<plugins>

<plugins>
<!-- native build -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<version>3.0.0</version>
<executions>
<execution>
<id>xcodebuild</id>
Expand All @@ -162,41 +138,17 @@
<argument>libjcocoa</argument>
<argument>-configuration</argument>
<argument>${xcodeScheme}</argument>
<argument>CONFIGURATION_BUILD_DIR=${basedir}/target/native/</argument>
<argument>CONFIGURATION_BUILD_DIR=${project.build.outputDirectory}</argument>
<argument>build</argument>
</arguments>
</configuration>
</plugin>

<!-- copy native libs -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>copy-native-libs</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/target/native/</directory>
<filtering>false</filtering>
</resource>
</resources>
<outputDirectory>${basedir}/target/classes/ca/weblite/objc</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>

<!-- add java 11 module name to manifest -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<version>3.2.0</version>
<configuration>
<archive>
<manifestEntries>
Expand All @@ -210,19 +162,12 @@
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>3.1.12.2</version>
<version>4.2.0</version>
<configuration>
<effort>more</effort>
<jvmArgs>--add-opens java.base/java.lang=ALL-UNNAMED
--illegal-access=deny</jvmArgs>
</configuration>
<dependencies>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs</artifactId>
<version>4.0.0-beta4</version>
</dependency>
</dependencies>
<executions>
<!-- Ensures that spotbugs inspects source code when project is deployed. -->
<!-- <execution> -->
Expand Down Expand Up @@ -251,10 +196,21 @@

<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.1.0</version>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
Expand All @@ -268,7 +224,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.1</version>
<version>3.2.0</version>
<configuration>
<failOnError>false</failOnError>
<!-- <additionalparam>-Xdoclint:none</additionalparam> -->
Expand Down Expand Up @@ -333,16 +289,9 @@

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.5.1</version>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>

</dependencies>
</project>
82 changes: 34 additions & 48 deletions src/main/java/ca/weblite/nativeutils/NativeUtils.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package ca.weblite.nativeutils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

/**
* Simple library class for working with JNI (Java Native Interface)
Expand All @@ -24,96 +25,81 @@ private NativeUtils() {
}

/**
* <p>loadLibraryFromJar.</p>
* Loads a library from current JAR archive, using the class loader of the {@code NativeUtils}
* class to find the resource in the JAR.
*
* @param path a {@link java.lang.String} object.
* @throws java.io.IOException if any.
* @throws UnsatisfiedLinkError if loading the native library fails.
*/
public static void loadLibraryFromJar(String path) throws IOException {
loadLibraryFromJar(path, NativeUtils.class);
}

/**
* Loads library from current JAR archive
* Loads a library from current JAR archive.
*
* The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after exiting.
* Method uses String as filename because the pathname is "abstract", not system-dependent.
*
* @throws java.lang.IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of @see File#createTempFile(java.lang.String, java.lang.String)).
* @throws java.lang.IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of @see File#createTempFile(java.lang.String, java.lang.String)).
* @throws java.lang.IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of @see File#createTempFile(java.lang.String, java.lang.String)).
* @param path a {@link java.lang.String} object.
* @param source a {@link java.lang.Class} object.
* @param source {@code Class} whose class loader should be used to look up the resource in the JAR file
* @throws java.io.IOException if any.
* @throws UnsatisfiedLinkError if loading the native library fails.
*/
public static void loadLibraryFromJar(String path, Class source) throws IOException {


public static void loadLibraryFromJar(String path, Class<?> source) throws IOException, UnsatisfiedLinkError {
// Finally, load the library
System.load(loadFileFromJar(path, source).getAbsolutePath());
System.load(extractFromJar(path, source).toAbsolutePath().toString());
}

/**
* <p>loadFileFromJar.</p>
* Extracts a resource from the JAR and stores it as temporary file
* in the file system.
*
* @param path a {@link java.lang.String} object.
* @param source a {@link java.lang.Class} object.
* @return a {@link java.io.File} object.
* @param path path of the resource, must begin with {@code '/'}, see {@link Class#getResourceAsStream(String)}
* @param source {@code Class} whose class loader should be used to look up the resource in the JAR file
* @return file path of the temporary file extracted from this JAR
* @throws java.io.IOException if any.
*/
public static File loadFileFromJar(String path, Class source) throws IOException {
public static Path extractFromJar(String path, Class<?> source) throws IOException {
if (!path.startsWith("/")) {
throw new IllegalArgumentException("The path has to be absolute (start with '/').");
}

// Obtain filename from path
String[] parts = path.split("/");
String filename = (parts.length > 1) ? parts[parts.length - 1] : null;
String filename = path.substring(path.lastIndexOf('/') + 1);

// Split filename to prexif and suffix (extension)
String prefix = "";
String suffix = null;
if (filename != null) {
parts = filename.split("\\.", 2);
prefix = parts[0];
suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; // Thanks, davs! :-)
// Split filename to prefix and suffix (extension)
String prefix;
String suffix;
int lastDot = filename.lastIndexOf('.');
if (lastDot == -1) {
// No file extension; use complete filename as prefix
prefix = filename;
suffix = null;
} else {
prefix = filename.substring(0, lastDot);
suffix = filename.substring(lastDot);
}

// Check if the filename is okay
if (filename == null || prefix.length() < 3) {
if (prefix.length() < 3) {
throw new IllegalArgumentException("The filename has to be at least 3 characters long.");
}

// Prepare temporary file
File temp = File.createTempFile(prefix, suffix);
temp.deleteOnExit();

if (!temp.exists()) {
throw new FileNotFoundException("File " + temp.getAbsolutePath() + " does not exist.");
}

// Prepare buffer for data copying
byte[] buffer = new byte[1024];
int readBytes;
Path temp = Files.createTempFile(prefix, suffix);
temp.toFile().deleteOnExit();

// Open and check input stream
InputStream is = source.getResourceAsStream(path);
if (is == null) {
throw new FileNotFoundException("File " + path + " was not found inside JAR.");
}

// Open output stream and copy data between source file in JAR and the temporary file
OutputStream os = new FileOutputStream(temp);
try {
while ((readBytes = is.read(buffer)) != -1) {
os.write(buffer, 0, readBytes);
}
} finally {
// If read/write fails, close streams safely before throwing an exception
os.close();
is.close();
try (is; OutputStream out = Files.newOutputStream(temp, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
is.transferTo(out);
}
return temp;

}
}
Loading