From b8b96291c6aa1d6cfed08b000cfc16e6231fbbe8 Mon Sep 17 00:00:00 2001 From: Adam Murdoch Date: Sat, 1 Sep 2012 10:29:43 +1000 Subject: [PATCH] Throw NativeIntegrationUnavailableException when an integration is not supported, and NativeException when something goes wrong loading the integration. --- readme.md | 2 +- .../net/rubygrapefruit/platform/Native.java | 38 +++++++++---------- ...NativeIntegrationUnavailableException.java | 10 +++++ .../platform/internal/Platform.java | 38 +++++++++++-------- 4 files changed, 50 insertions(+), 38 deletions(-) create mode 100644 src/main/java/net/rubygrapefruit/platform/NativeIntegrationUnavailableException.java diff --git a/readme.md b/readme.md index 93d58b6..d7f0750 100755 --- a/readme.md +++ b/readme.md @@ -126,7 +126,7 @@ You can run `$INSTALL_DIR/bin/native-platform` to run the test application. * Split into multiple projects. * Convert to c. * Thread safety. -* Improve error message when unsupported capability is used. +* Make native library extraction multi-process safe. * Initial release. * Use fully decomposed form for unicode file names on hfs+ filesystems. * Handle string encoding for file system details. diff --git a/src/main/java/net/rubygrapefruit/platform/Native.java b/src/main/java/net/rubygrapefruit/platform/Native.java index 9d4a957..2615e40 100755 --- a/src/main/java/net/rubygrapefruit/platform/Native.java +++ b/src/main/java/net/rubygrapefruit/platform/Native.java @@ -26,9 +26,6 @@ public class Native { synchronized (lock) { if (!loaded) { Platform platform = Platform.current(); - if (!platform.isSupported()) { - throw new NativeException(String.format("The current platform is not supported.")); - } try { File libFile; URL resource = Native.class.getClassLoader().getResource(platform.getLibraryName()); @@ -46,16 +43,18 @@ public class Native { libFile = new File("build/binaries/" + platform.getLibraryName()); } System.load(libFile.getCanonicalPath()); - } catch (IOException e) { - throw new RuntimeException(e); + int nativeVersion = NativeLibraryFunctions.getVersion(); + if (nativeVersion != NativeLibraryFunctions.VERSION) { + throw new NativeException(String.format( + "Unexpected native library version loaded. Expected %s, was %s.", nativeVersion, + NativeLibraryFunctions.VERSION)); + } + loaded = true; + } catch (NativeException e) { + throw e; + } catch (Exception e) { + throw new NativeException("Failed to initialise native integration.", e); } - int nativeVersion = NativeLibraryFunctions.getVersion(); - if (nativeVersion != NativeLibraryFunctions.VERSION) { - throw new NativeException(String.format( - "Unexpected native library version loaded. Expected %s, was %s.", nativeVersion, - NativeLibraryFunctions.VERSION)); - } - loaded = true; } } } @@ -64,18 +63,15 @@ public class Native { * Locates a native integration of the given type. * * @return The native integration. - * @throws UnsupportedOperationException if the given integration is not available. + * @throws NativeIntegrationUnavailableException When the given native integration is not available on the current + * machine. + * @throws NativeException On failure to load the native integration. */ - public static T get(Class type) throws UnsupportedOperationException { + public static T get(Class type) + throws NativeIntegrationUnavailableException, NativeException { init(null); Platform platform = Platform.current(); - T integration = platform.get(type); - if (integration != null) { - return integration; - } - - throw new UnsupportedOperationException(String.format("Cannot load unsupported native integration %s.", - type.getName())); + return platform.get(type); } private static void copy(URL source, File dest) { diff --git a/src/main/java/net/rubygrapefruit/platform/NativeIntegrationUnavailableException.java b/src/main/java/net/rubygrapefruit/platform/NativeIntegrationUnavailableException.java new file mode 100644 index 0000000..b9e6708 --- /dev/null +++ b/src/main/java/net/rubygrapefruit/platform/NativeIntegrationUnavailableException.java @@ -0,0 +1,10 @@ +package net.rubygrapefruit.platform; + +/** + * Thrown when a given integration is not available for the current machine. + */ +public class NativeIntegrationUnavailableException extends NativeException { + public NativeIntegrationUnavailableException(String message) { + super(message); + } +} diff --git a/src/main/java/net/rubygrapefruit/platform/internal/Platform.java b/src/main/java/net/rubygrapefruit/platform/internal/Platform.java index cd00e88..589b803 100755 --- a/src/main/java/net/rubygrapefruit/platform/internal/Platform.java +++ b/src/main/java/net/rubygrapefruit/platform/internal/Platform.java @@ -10,8 +10,8 @@ public abstract class Platform { public static Platform current() { synchronized (Platform.class) { if (platform == null) { - String osName = System.getProperty("os.name").toLowerCase(); - String arch = System.getProperty("os.arch"); + String osName = getOperatingSystem().toLowerCase(); + String arch = getArchitecture(); if (osName.contains("windows")) { platform = new Windows(); } else if (osName.contains("linux")) { @@ -28,19 +28,16 @@ public abstract class Platform { } } - public boolean isSupported() { - return true; - } - public boolean isWindows() { return false; } public T get(Class type) { - return null; + throw new NativeIntegrationUnavailableException(String.format("Native integration %s is not supported on this operating system (%s %s)", + type.getName(), getOperatingSystem(), getArchitecture())); } - public abstract String getLibraryName(); + public abstract String getLibraryName() throws NativeIntegrationUnavailableException; private static class Windows extends Platform { @Override @@ -105,13 +102,21 @@ public abstract class Platform { @Override public String getLibraryName() { - if (System.getProperty("os.arch").equals("amd64")) { + if (getArchitecture().equals("amd64")) { return "libnative-linux-amd64.so"; } - return "libnative-linux-i386.so"; + if (getArchitecture().equals("i386")) { + return "libnative-linux-i386.so"; + } + throw new NativeIntegrationUnavailableException(String.format( + "Native integration is not available for this architecture (%s) on Linux.", getArchitecture())); } } + private static String getArchitecture() { + return System.getProperty("os.arch"); + } + private static class Solaris extends Unix { @Override public String getLibraryName() { @@ -135,13 +140,14 @@ public abstract class Platform { } private static class Unsupported extends Platform { - @Override - public boolean isSupported() { - return false; - } - public String getLibraryName() { - throw new UnsupportedOperationException(); + throw new NativeIntegrationUnavailableException(String.format( + "Native integration is not available for this operating system (%s %s)", getOperatingSystem(), + getArchitecture())); } } + + private static String getOperatingSystem() { + return System.getProperty("os.name"); + } }