mirror of
https://gitee.com/dolphinscheduler/DolphinScheduler.git
synced 2024-12-01 19:58:29 +08:00
access field handle of FileDescriptor in ProcessImplForWin32 by reflection for portability (#2113)
* access field handle of FileDescriptor in ProcessImplForWin32 by reflection for portability Current implementation relies on `sun.misc.JavaIOFileDescriptorAccess` which is only accessible on oraclejdk8. Basically the demand is getting & setting `handle` field of `FileDescriptor`, so we can directly do that with reflection. Though, I suspect the necessity we introduce ProcessImplForWin32. Maybe we could have a better way to support worker server to run bat script. * harden initialization of ProcessImplForWin32 * ignore ShellTaskTest#testHandleForWindows outside Windows
This commit is contained in:
parent
450a1f56fc
commit
9224b49b58
@ -400,8 +400,7 @@ public class OSUtils {
|
||||
* @return true if mac
|
||||
*/
|
||||
public static boolean isMacOS() {
|
||||
String os = System.getProperty("os.name");
|
||||
return os.startsWith("Mac");
|
||||
return getOSName().startsWith("Mac");
|
||||
}
|
||||
|
||||
|
||||
@ -409,9 +408,16 @@ public class OSUtils {
|
||||
* whether is windows
|
||||
* @return true if windows
|
||||
*/
|
||||
public static boolean isWindows() {
|
||||
String os = System.getProperty("os.name");
|
||||
return os.startsWith("Windows");
|
||||
public static boolean isWindows() { ;
|
||||
return getOSName().startsWith("Windows");
|
||||
}
|
||||
|
||||
/**
|
||||
* get current OS name
|
||||
* @return current OS name
|
||||
*/
|
||||
public static String getOSName() {
|
||||
return System.getProperty("os.name");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,8 @@ package org.apache.dolphinscheduler.common.utils.process;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.platform.win32.*;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import java.lang.reflect.Field;
|
||||
import org.apache.dolphinscheduler.common.utils.OSUtils;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
import java.io.*;
|
||||
@ -31,10 +33,25 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.sun.jna.platform.win32.WinBase.STILL_ACTIVE;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class ProcessImplForWin32 extends Process {
|
||||
private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
|
||||
= sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
|
||||
|
||||
private static final Field FD_HANDLE;
|
||||
|
||||
static {
|
||||
if (!OSUtils.isWindows()) {
|
||||
throw new RuntimeException("ProcessImplForWin32 can be only initialized in " +
|
||||
"Windows environment, but current OS is " + OSUtils.getOSName());
|
||||
}
|
||||
|
||||
try {
|
||||
FD_HANDLE = requireNonNull(FileDescriptor.class.getDeclaredField("handle"));
|
||||
FD_HANDLE.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int PIPE_SIZE = 4096 + 24;
|
||||
|
||||
@ -46,6 +63,22 @@ public class ProcessImplForWin32 extends Process {
|
||||
|
||||
private static final WinNT.HANDLE JAVA_INVALID_HANDLE_VALUE = new WinNT.HANDLE(Pointer.createConstant(-1));
|
||||
|
||||
private static void setHandle(FileDescriptor obj, long handle) {
|
||||
try {
|
||||
FD_HANDLE.set(obj, handle);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static long getHandle(FileDescriptor obj) {
|
||||
try {
|
||||
return (Long) FD_HANDLE.get(obj);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a file for writing. If {@code append} is {@code true} then the file
|
||||
* is opened for atomic append directly and a FileOutputStream constructed
|
||||
@ -63,7 +96,7 @@ public class ProcessImplForWin32 extends Process {
|
||||
sm.checkWrite(path);
|
||||
long handle = openForAtomicAppend(path);
|
||||
final FileDescriptor fd = new FileDescriptor();
|
||||
fdAccess.setHandle(fd, handle);
|
||||
setHandle(fd, handle);
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<FileOutputStream>() {
|
||||
public FileOutputStream run() {
|
||||
@ -102,30 +135,30 @@ public class ProcessImplForWin32 extends Process {
|
||||
if (redirects[0] == ProcessBuilderForWin32.Redirect.PIPE)
|
||||
stdHandles[0] = -1L;
|
||||
else if (redirects[0] == ProcessBuilderForWin32.Redirect.INHERIT)
|
||||
stdHandles[0] = fdAccess.getHandle(FileDescriptor.in);
|
||||
stdHandles[0] = getHandle(FileDescriptor.in);
|
||||
else {
|
||||
f0 = new FileInputStream(redirects[0].file());
|
||||
stdHandles[0] = fdAccess.getHandle(f0.getFD());
|
||||
stdHandles[0] = getHandle(f0.getFD());
|
||||
}
|
||||
|
||||
if (redirects[1] == ProcessBuilderForWin32.Redirect.PIPE)
|
||||
stdHandles[1] = -1L;
|
||||
else if (redirects[1] == ProcessBuilderForWin32.Redirect.INHERIT)
|
||||
stdHandles[1] = fdAccess.getHandle(FileDescriptor.out);
|
||||
stdHandles[1] = getHandle(FileDescriptor.out);
|
||||
else {
|
||||
f1 = newFileOutputStream(redirects[1].file(),
|
||||
redirects[1].append());
|
||||
stdHandles[1] = fdAccess.getHandle(f1.getFD());
|
||||
stdHandles[1] = getHandle(f1.getFD());
|
||||
}
|
||||
|
||||
if (redirects[2] == ProcessBuilderForWin32.Redirect.PIPE)
|
||||
stdHandles[2] = -1L;
|
||||
else if (redirects[2] == ProcessBuilderForWin32.Redirect.INHERIT)
|
||||
stdHandles[2] = fdAccess.getHandle(FileDescriptor.err);
|
||||
stdHandles[2] = getHandle(FileDescriptor.err);
|
||||
else {
|
||||
f2 = newFileOutputStream(redirects[2].file(),
|
||||
redirects[2].append());
|
||||
stdHandles[2] = fdAccess.getHandle(f2.getFD());
|
||||
stdHandles[2] = getHandle(f2.getFD());
|
||||
}
|
||||
}
|
||||
|
||||
@ -442,7 +475,7 @@ public class ProcessImplForWin32 extends Process {
|
||||
stdin_stream = ProcessBuilderForWin32.NullOutputStream.INSTANCE;
|
||||
else {
|
||||
FileDescriptor stdin_fd = new FileDescriptor();
|
||||
fdAccess.setHandle(stdin_fd, stdHandles[0]);
|
||||
setHandle(stdin_fd, stdHandles[0]);
|
||||
stdin_stream = new BufferedOutputStream(
|
||||
new FileOutputStream(stdin_fd));
|
||||
}
|
||||
@ -451,7 +484,7 @@ public class ProcessImplForWin32 extends Process {
|
||||
stdout_stream = ProcessBuilderForWin32.NullInputStream.INSTANCE;
|
||||
else {
|
||||
FileDescriptor stdout_fd = new FileDescriptor();
|
||||
fdAccess.setHandle(stdout_fd, stdHandles[1]);
|
||||
setHandle(stdout_fd, stdHandles[1]);
|
||||
stdout_stream = new BufferedInputStream(
|
||||
new FileInputStream(stdout_fd));
|
||||
}
|
||||
@ -460,7 +493,7 @@ public class ProcessImplForWin32 extends Process {
|
||||
stderr_stream = ProcessBuilderForWin32.NullInputStream.INSTANCE;
|
||||
else {
|
||||
FileDescriptor stderr_fd = new FileDescriptor();
|
||||
fdAccess.setHandle(stderr_fd, stdHandles[2]);
|
||||
setHandle(stderr_fd, stdHandles[2]);
|
||||
stderr_stream = new FileInputStream(stderr_fd);
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -172,7 +173,7 @@ public class ShellTaskTest {
|
||||
@Test
|
||||
public void testHandleForWindows() throws Exception {
|
||||
try {
|
||||
PowerMockito.when(OSUtils.isWindows()).thenReturn(true);
|
||||
Assume.assumeTrue(OSUtils.isWindows());
|
||||
shellTask.handle();
|
||||
Assert.assertTrue(true);
|
||||
} catch (Error | Exception e) {
|
||||
|
Loading…
Reference in New Issue
Block a user