Skip to content

Commit

Permalink
Load multiple native libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
lukepalmer committed Sep 22, 2016
1 parent e1b3d7e commit 8c8d55a
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 48 deletions.
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
addons:
# hostname monkeying needed for openjdk, see travis-ci/travis-ci#5227 for details
hosts:
- myshorthost
hostname: myshorthost
before_install:
- sudo add-apt-repository ppa:trevorbernard/zeromq -y
- sudo apt-get update -y
Expand Down Expand Up @@ -30,3 +35,4 @@ script: mvn test
jdk:
- openjdk6
- openjdk7
- oraclejdk8
3 changes: 2 additions & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Alexej Lotz
Asko Kauppi
Barak Amar
Bernd Prager
Chris Busbey
Chris Wong
Conrad D. Steenberg
Dhruva Krishnamurthy
Expand All @@ -17,6 +18,7 @@ Gonzalo Diethelm
Joe Thornber
Jon Dyte
Kamil Shakirov
Luke Palmer
Martin Hurton
Martin Lucina
Martin Sustrik
Expand All @@ -31,7 +33,6 @@ Tero Marttila
Terry Wilson
Trevor Bernard
Vitaly Mayatskikh
Chris Busbey

Credits
=======
Expand Down
16 changes: 16 additions & 0 deletions jzmq-jni/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@
</profile>
</profiles>

<dependencies>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
<version>1.6.4</version>
<scope>test</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.4</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
Expand Down
87 changes: 41 additions & 46 deletions jzmq-jni/src/main/java/org/zeromq/EmbeddedLibraryTools.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
package org.zeromq;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -22,6 +17,9 @@ public class EmbeddedLibraryTools {
LOADED_EMBEDDED_LIBRARY = loadEmbeddedLibrary();
}

private EmbeddedLibraryTools() {
}

public static String getCurrentPlatformIdentifier() {
String osName = System.getProperty("os.name");
if (osName.toLowerCase().contains("windows")) {
Expand Down Expand Up @@ -66,7 +64,7 @@ private static void catalogArchive(final File jarfile, final Collection<String>
} finally {
try {
j.close();
} catch(Exception e) {
} catch (Exception e) {
}
}

Expand Down Expand Up @@ -112,54 +110,51 @@ private static boolean loadEmbeddedLibrary() {

// attempt to locate embedded native library within JAR at following location:
// /NATIVE/${os.arch}/${os.name}/libjzmq.[so|dylib|dll]
String[] allowedExtensions = new String[] { "so", "dylib", "dll" };
String[] allowedExtensions = new String[]{"so", "dylib", "dll"};
String[] libs;
final String libsFromProps = System.getProperty("jzmq.libs");
if (libsFromProps == null)
libs = new String[]{"libsodium", "libzmq", "libjzmq"};
else
libs = libsFromProps.split(",");
StringBuilder url = new StringBuilder();
url.append("/NATIVE/");
url.append(getCurrentPlatformIdentifier());
url.append("/libjzmq.");
URL nativeLibraryUrl = null;
// loop through extensions, stopping after finding first one
for (String ext : allowedExtensions) {
nativeLibraryUrl = ZMQ.class.getResource(url.toString() + ext);
if (nativeLibraryUrl != null)
break;
}

if (nativeLibraryUrl != null) {

// native library found within JAR, extract and load

try {

final File libfile = File.createTempFile("libjzmq-", ".lib");
libfile.deleteOnExit(); // just in case

final InputStream in = nativeLibraryUrl.openStream();
final OutputStream out = new BufferedOutputStream(new FileOutputStream(libfile));
url.append(getCurrentPlatformIdentifier()).append("/");
for (String lib : libs) {
URL nativeLibraryUrl = null;
// loop through extensions, stopping after finding first one
for (String ext : allowedExtensions) {
nativeLibraryUrl = ZMQ.class.getResource(url.toString() + lib + "." + ext);
if (nativeLibraryUrl != null)
break;
}

int len = 0;
byte[] buffer = new byte[8192];
while ((len = in.read(buffer)) > -1)
out.write(buffer, 0, len);
out.close();
in.close();
if (nativeLibraryUrl != null) {
// native library found within JAR, extract and load
try {

System.load(libfile.getAbsolutePath());
final File libfile = File.createTempFile(lib, ".lib");
libfile.deleteOnExit(); // just in case

libfile.delete();
final InputStream in = nativeLibraryUrl.openStream();
final OutputStream out = new BufferedOutputStream(new FileOutputStream(libfile));

usingEmbedded = true;
int len = 0;
byte[] buffer = new byte[8192];
while ((len = in.read(buffer)) > -1)
out.write(buffer, 0, len);
out.close();
in.close();
System.load(libfile.getAbsolutePath());

} catch (IOException x) {
// mission failed, do nothing
}
usingEmbedded = true;

} // nativeLibraryUrl exists
} catch (IOException x) {
// mission failed, do nothing
}

} // nativeLibraryUrl exists
}
return usingEmbedded;

}

private EmbeddedLibraryTools() {
}
}
46 changes: 46 additions & 0 deletions jzmq-jni/src/test/java/org/zeromq/EmbeddedLibraryToolsTest.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package org.zeromq;

import org.easymock.Capture;
import org.easymock.CaptureType;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.newCapture;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.powermock.api.easymock.PowerMock.*;

/**
* Exercises basic manipulations in the EmbeddedLibraryTools for JNI loading.
* Does not give full coverage yet as this has to be per-platform.
*/
@RunWith(PowerMockRunner.class)
public class EmbeddedLibraryToolsTest {
private static final String origOsName = System.getProperty("os.name");

Expand Down Expand Up @@ -46,6 +56,42 @@ public void rewriteSpacesInPath() {
assertPlatformIdentifierEquals("alpha/Digital_Unix");
}

@Test
@PrepareForTest(EmbeddedLibraryTools.class)
public void multiLibLoad() throws Exception {
mockStaticPartial(System.class, "load");
Capture<String> loadCapture = newCapture(CaptureType.ALL);
System.load(capture(loadCapture));
expectLastCall().times(2);
replayAll();
setOsProperties("Linux", "testarch");
assertTrue(EmbeddedLibraryTools.LOADED_EMBEDDED_LIBRARY);
verifyAll();
assertTrue(loadCapture.getValues().get(0).contains("libzmq"));
assertTrue(loadCapture.getValues().get(1).contains("libjzmq"));
}

@Test
@PrepareForTest(EmbeddedLibraryTools.class)
public void libsAsProp() throws Exception {
try {
System.setProperty("jzmq.libs", "foo,libjzmq");
mockStaticPartial(System.class, "load");
Capture<String> loadCapture = newCapture(CaptureType.ALL);
System.load(capture(loadCapture));
expectLastCall().times(2);
replayAll();
setOsProperties("Linux", "testarch");
assertTrue(EmbeddedLibraryTools.LOADED_EMBEDDED_LIBRARY);
verifyAll();
assertTrue(loadCapture.getValues().get(0).contains("foo"));
assertTrue(loadCapture.getValues().get(1).contains("libjzmq"));
} finally {
System.clearProperty("jzmq.libs");
}
}


@After
public void resetOsProperties() {
setOsProperties(origOsName, origOsArch);
Expand Down
Empty file.
Empty file.
Empty file.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down

0 comments on commit 8c8d55a

Please sign in to comment.