package net.rubygrapefruit.platform; import net.rubygrapefruit.platform.internal.*; import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions; import java.io.*; import java.net.URL; /** * Provides access to the native integrations. Use {@link #get(Class)} to load a particular integration. */ public class Native { private static final Object lock = new Object(); private static boolean loaded; /** * Initialises the native integration, if not already initialized. * * @param extractDir The directory to extract native resources into. May be null. */ static void init(File extractDir) { 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()); if (resource != null) { File libDir = extractDir; if (libDir == null) { libDir = File.createTempFile("native-platform", "dir"); libDir.delete(); libDir.mkdirs(); } libFile = new File(libDir, platform.getLibraryName()); libFile.deleteOnExit(); copy(resource, libFile); } else { 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; } } } static T get(Class type) { init(null); Platform platform = Platform.current(); if (platform.isPosix()) { if (type.equals(PosixFile.class)) { return type.cast(new DefaultPosixFile()); } if (type.equals(Process.class)) { return type.cast(new DefaultProcess()); } if (type.equals(TerminalAccess.class)) { return type.cast(new TerminfoTerminalAccess()); } if (type.equals(SystemInfo.class)) { MutableSystemInfo systemInfo = new MutableSystemInfo(); FunctionResult result = new FunctionResult(); NativeLibraryFunctions.getSystemInfo(systemInfo, result); if (result.isFailed()) { throw new NativeException(String.format("Could not fetch system information: %s", result.getMessage())); } System.out.println("=> CHARACTER ENCODING: " + systemInfo.characterEncoding); return type.cast(systemInfo); } } else if (platform.isWindows()) { if (type.equals(Process.class)) { return type.cast(new DefaultProcess()); } if (type.equals(TerminalAccess.class)) { return type.cast(new WindowsTerminalAccess()); } } if (platform.isOsX()) { if (type.equals(FileSystems.class)) { return type.cast(new PosixFileSystems()); } } throw new UnsupportedOperationException(String.format("Cannot load unsupported native integration %s.", type.getName())); } private static void copy(URL source, File dest) { try { InputStream inputStream = source.openStream(); try { OutputStream outputStream = new FileOutputStream(dest); try { byte[] buffer = new byte[4096]; while (true) { int nread = inputStream.read(buffer); if (nread < 0) { break; } outputStream.write(buffer, 0, nread); } } finally { outputStream.close(); } } finally { inputStream.close(); } } catch (IOException e) { throw new NativeException(String.format("Could not extract native JNI library."), e); } } }