- Changed Native.get() to cache integration instances.
- Extracted DefaultSystemInfo out of a couple of separate places.
This commit is contained in:
@@ -5,6 +5,8 @@ import net.rubygrapefruit.platform.internal.Platform;
|
|||||||
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
||||||
|
|
||||||
import java.io.File;
|
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.
|
* Provides access to the native integrations. Use {@link #get(Class)} to load a particular integration.
|
||||||
@@ -12,6 +14,7 @@ import java.io.File;
|
|||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
public class Native {
|
public class Native {
|
||||||
private static boolean loaded;
|
private static boolean loaded;
|
||||||
|
private static final Map<Class<?>, Object> integrations = new HashMap<Class<?>, Object>();
|
||||||
|
|
||||||
private Native() {
|
private Native() {
|
||||||
}
|
}
|
||||||
@@ -59,13 +62,19 @@ public class Native {
|
|||||||
public static <T extends NativeIntegration> T get(Class<T> type)
|
public static <T extends NativeIntegration> T get(Class<T> type)
|
||||||
throws NativeIntegrationUnavailableException, NativeException {
|
throws NativeIntegrationUnavailableException, NativeException {
|
||||||
init(null);
|
init(null);
|
||||||
try {
|
synchronized (Native.class) {
|
||||||
Platform platform = Platform.current();
|
Object instance = integrations.get(type);
|
||||||
return platform.get(type);
|
if (instance == null) {
|
||||||
} catch (NativeException e) {
|
try {
|
||||||
throw e;
|
instance = Platform.current().get(type);
|
||||||
} catch (Throwable t) {
|
} catch (NativeException e) {
|
||||||
throw new NativeException(String.format("Failed to load native integration %s.", type.getSimpleName()), t);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import net.rubygrapefruit.platform.Terminal;
|
|||||||
import net.rubygrapefruit.platform.Terminals;
|
import net.rubygrapefruit.platform.Terminals;
|
||||||
|
|
||||||
public abstract class AbstractTerminals implements Terminals {
|
public abstract class AbstractTerminals implements Terminals {
|
||||||
private static Output currentlyOpen;
|
private final Object lock = new Object();
|
||||||
private static AbstractTerminal current;
|
private Output currentlyOpen;
|
||||||
|
private AbstractTerminal current;
|
||||||
|
|
||||||
public Terminal getTerminal(Output output) {
|
public Terminal getTerminal(Output output) {
|
||||||
synchronized (AbstractTerminals.class) {
|
synchronized (lock) {
|
||||||
if (currentlyOpen != null && currentlyOpen != output) {
|
if (currentlyOpen != null && currentlyOpen != output) {
|
||||||
throw new UnsupportedOperationException("Currently only one output can be used as a terminal.");
|
throw new UnsupportedOperationException("Currently only one output can be used as a terminal.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package net.rubygrapefruit.platform.internal;
|
|||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
import net.rubygrapefruit.platform.NativeException;
|
||||||
import net.rubygrapefruit.platform.PosixFile;
|
import net.rubygrapefruit.platform.PosixFile;
|
||||||
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.PosixFileFunctions;
|
import net.rubygrapefruit.platform.internal.jni.PosixFileFunctions;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -12,14 +11,8 @@ public class DefaultPosixFile implements PosixFile {
|
|||||||
private final String characterEncoding;
|
private final String characterEncoding;
|
||||||
|
|
||||||
public DefaultPosixFile() {
|
public DefaultPosixFile() {
|
||||||
MutableSystemInfo systemInfo = new MutableSystemInfo();
|
DefaultSystemInfo systemInfo = new DefaultSystemInfo();
|
||||||
FunctionResult result = new FunctionResult();
|
this.characterEncoding = systemInfo.getCharacterEncoding();
|
||||||
NativeLibraryFunctions.getSystemInfo(systemInfo, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not fetch system information: %s",
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
this.characterEncoding = systemInfo.characterEncoding;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMode(File file, int perms) {
|
public void setMode(File file, int perms) {
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package net.rubygrapefruit.platform.internal;
|
||||||
|
|
||||||
|
import net.rubygrapefruit.platform.NativeException;
|
||||||
|
import net.rubygrapefruit.platform.SystemInfo;
|
||||||
|
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
||||||
|
|
||||||
|
public class DefaultSystemInfo implements SystemInfo {
|
||||||
|
MutableSystemInfo systemInfo = new MutableSystemInfo();
|
||||||
|
|
||||||
|
public DefaultSystemInfo() {
|
||||||
|
FunctionResult result = new FunctionResult();
|
||||||
|
NativeLibraryFunctions.getSystemInfo(systemInfo, result);
|
||||||
|
if (result.isFailed()) {
|
||||||
|
throw new NativeException(String.format("Could not fetch system information: %s",
|
||||||
|
result.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKernelName() {
|
||||||
|
return systemInfo.getKernelName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKernelVersion() {
|
||||||
|
return systemInfo.getKernelVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMachineArchitecture() {
|
||||||
|
return systemInfo.getMachineArchitecture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCharacterEncoding() {
|
||||||
|
return systemInfo.characterEncoding;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package net.rubygrapefruit.platform.internal;
|
|||||||
|
|
||||||
import net.rubygrapefruit.platform.*;
|
import net.rubygrapefruit.platform.*;
|
||||||
import net.rubygrapefruit.platform.Process;
|
import net.rubygrapefruit.platform.Process;
|
||||||
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
|
||||||
|
|
||||||
public abstract class Platform {
|
public abstract class Platform {
|
||||||
private static Platform platform;
|
private static Platform platform;
|
||||||
@@ -75,14 +74,7 @@ public abstract class Platform {
|
|||||||
return type.cast(new TerminfoTerminals());
|
return type.cast(new TerminfoTerminals());
|
||||||
}
|
}
|
||||||
if (type.equals(SystemInfo.class)) {
|
if (type.equals(SystemInfo.class)) {
|
||||||
MutableSystemInfo systemInfo = new MutableSystemInfo();
|
return type.cast(new DefaultSystemInfo());
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
NativeLibraryFunctions.getSystemInfo(systemInfo, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not fetch system information: %s",
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
return type.cast(systemInfo);
|
|
||||||
}
|
}
|
||||||
return super.get(type);
|
return super.get(type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ class FileSystemsTest extends Specification {
|
|||||||
@Rule TemporaryFolder tmpDir
|
@Rule TemporaryFolder tmpDir
|
||||||
final FileSystems fileSystems = Native.get(FileSystems.class)
|
final FileSystems fileSystems = Native.get(FileSystems.class)
|
||||||
|
|
||||||
|
def "caches file systems instance"() {
|
||||||
|
expect:
|
||||||
|
Native.get(FileSystems.class) == fileSystems
|
||||||
|
}
|
||||||
|
|
||||||
def "can query filesystem details"() {
|
def "can query filesystem details"() {
|
||||||
expect:
|
expect:
|
||||||
fileSystems.fileSystems.collect() { it.mountPoint }.containsAll(File.listRoots())
|
fileSystems.fileSystems.collect() { it.mountPoint }.containsAll(File.listRoots())
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ class PosixFileTest extends Specification {
|
|||||||
@Rule TemporaryFolder tmpDir
|
@Rule TemporaryFolder tmpDir
|
||||||
final PosixFile file = Native.get(PosixFile.class)
|
final PosixFile file = Native.get(PosixFile.class)
|
||||||
|
|
||||||
|
def "caches file instance"() {
|
||||||
|
expect:
|
||||||
|
Native.get(PosixFile.class) == file
|
||||||
|
}
|
||||||
|
|
||||||
def "can set mode on a file"() {
|
def "can set mode on a file"() {
|
||||||
def testFile = tmpDir.newFile("test.txt")
|
def testFile = tmpDir.newFile("test.txt")
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ class ProcessTest extends Specification {
|
|||||||
@Rule TemporaryFolder tmpDir
|
@Rule TemporaryFolder tmpDir
|
||||||
final Process process = Native.get(Process.class)
|
final Process process = Native.get(Process.class)
|
||||||
|
|
||||||
|
def "caches process instance"() {
|
||||||
|
expect:
|
||||||
|
Native.get(Process.class) == process
|
||||||
|
}
|
||||||
|
|
||||||
def "can get PID"() {
|
def "can get PID"() {
|
||||||
expect:
|
expect:
|
||||||
process.getProcessId() != 0
|
process.getProcessId() != 0
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ class SystemInfoTest extends Specification {
|
|||||||
@Rule TemporaryFolder tmpDir
|
@Rule TemporaryFolder tmpDir
|
||||||
final SystemInfo systemInfo = Native.get(SystemInfo.class)
|
final SystemInfo systemInfo = Native.get(SystemInfo.class)
|
||||||
|
|
||||||
|
def "caches system info instance"() {
|
||||||
|
expect:
|
||||||
|
Native.get(SystemInfo.class) == systemInfo
|
||||||
|
}
|
||||||
|
|
||||||
def "can query OS details"() {
|
def "can query OS details"() {
|
||||||
expect:
|
expect:
|
||||||
systemInfo.kernelName
|
systemInfo.kernelName
|
||||||
|
|||||||
@@ -8,18 +8,23 @@ import spock.lang.IgnoreIf
|
|||||||
|
|
||||||
class TerminalsTest extends Specification {
|
class TerminalsTest extends Specification {
|
||||||
@Rule TemporaryFolder tmpDir
|
@Rule TemporaryFolder tmpDir
|
||||||
final Terminals terminal = Native.get(Terminals.class)
|
final Terminals terminals = Native.get(Terminals.class)
|
||||||
|
|
||||||
|
def "caches terminals instance"() {
|
||||||
|
expect:
|
||||||
|
Native.get(Terminals.class) == terminals
|
||||||
|
}
|
||||||
|
|
||||||
def "can check if attached to terminal"() {
|
def "can check if attached to terminal"() {
|
||||||
expect:
|
expect:
|
||||||
!terminal.isTerminal(Terminals.Output.Stdout);
|
!terminals.isTerminal(Terminals.Output.Stdout);
|
||||||
!terminal.isTerminal(Terminals.Output.Stderr);
|
!terminals.isTerminal(Terminals.Output.Stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@IgnoreIf({Platform.current().windows})
|
@IgnoreIf({Platform.current().windows})
|
||||||
def "cannot access posix terminal from a test"() {
|
def "cannot access posix terminal from a test"() {
|
||||||
when:
|
when:
|
||||||
terminal.getTerminal(Terminals.Output.Stdout)
|
terminals.getTerminal(Terminals.Output.Stdout)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
NativeException e = thrown()
|
NativeException e = thrown()
|
||||||
@@ -29,7 +34,7 @@ class TerminalsTest extends Specification {
|
|||||||
@IgnoreIf({!Platform.current().windows})
|
@IgnoreIf({!Platform.current().windows})
|
||||||
def "cannot access windows console from a test"() {
|
def "cannot access windows console from a test"() {
|
||||||
when:
|
when:
|
||||||
terminal.getTerminal(Terminals.Output.Stdout)
|
terminals.getTerminal(Terminals.Output.Stdout)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
NativeException e = thrown()
|
NativeException e = thrown()
|
||||||
|
|||||||
Reference in New Issue
Block a user