package net.rubygrapefruit.platform; import net.rubygrapefruit.platform.internal.NativeLibraryLoader; import net.rubygrapefruit.platform.internal.NativeLibraryLocator; import net.rubygrapefruit.platform.internal.Platform; import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions; import java.io.File; import java.util.HashMap; import java.util.Map; /** * Provides access to the native integrations. Use {@link #get(Class)} to load a particular integration. */ @ThreadSafe public class Native { private static NativeLibraryLoader loader; private static final Map, Object> integrations = new HashMap, Object>(); private Native() { } /** * Initialises the native integration, if not already initialized. * * @param extractDir The directory to extract native resources into. May be null, in which case a default is * selected. * * @throws NativeIntegrationUnavailableException When native integration is not available on the current machine. * @throws NativeException On failure to load the native integration. */ @ThreadSafe static public void init(File extractDir) throws NativeIntegrationUnavailableException, NativeException { synchronized (Native.class) { if (loader == null) { Platform platform = Platform.current(); try { loader = new NativeLibraryLoader(new NativeLibraryLocator(extractDir)); loader.load(platform.getLibraryName()); 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)); } } catch (NativeException e) { throw e; } catch (Throwable t) { throw new NativeException("Failed to initialise native integration.", t); } } } } /** * Locates a native integration of the given type. * * @return The native integration. Never returns null. * @throws NativeIntegrationUnavailableException When the given native integration is not available on the current * machine. * @throws NativeException On failure to load the native integration. */ @ThreadSafe public static T get(Class type) throws NativeIntegrationUnavailableException, NativeException { init(null); synchronized (Native.class) { Object instance = integrations.get(type); if (instance == null) { try { instance = Platform.current().get(type, loader); } catch (NativeException e) { throw e; } catch (Throwable t) { throw new NativeException(String.format("Failed to load native integration %s.", type.getSimpleName()), t); } integrations.put(type, instance); } return type.cast(instance); } } }