diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/process/ProcessBuilderForWin32.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/process/ProcessBuilderForWin32.java deleted file mode 100644 index 9d51eaec1c..0000000000 --- a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/process/ProcessBuilderForWin32.java +++ /dev/null @@ -1,1107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.dolphinscheduler.common.utils.process; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -/** - * This class is used to create operating system processes. - * - *

Each {@code ProcessBuilderForWindows} instance manages a collection - * of process attributes. The {@link #start()} method creates a new - * {@link Process} instance with those attributes. The {@link - * #start()} method can be invoked repeatedly from the same instance - * to create new subprocesses with identical or related attributes. - * - *

Each process builder manages these process attributes: - * - *

- * - *

Modifying a process builder's attributes will affect processes - * subsequently started by that object's {@link #start()} method, but - * will never affect previously started processes or the Java process - * itself. - * - *

Most error checking is performed by the {@link #start()} method. - * It is possible to modify the state of an object so that {@link - * #start()} will fail. For example, setting the command attribute to - * an empty list will not throw an exception unless {@link #start()} - * is invoked. - * - *

Note that this class is not synchronized. - * If multiple threads access a {@code ProcessBuilderForWindows} instance - * concurrently, and at least one of the threads modifies one of the - * attributes structurally, it must be synchronized externally. - * - *

Starting a new process which uses the default working directory - * and environment is easy: - * - *

 {@code
- * Process p = new ProcessBuilderForWindows("myCommand", "myArg").start();
- * }
- * - *

Here is an example that starts a process with a modified working - * directory and environment, and redirects standard output and error - * to be appended to a log file: - * - *

 {@code
- * ProcessBuilderForWindows pb =
- *   new ProcessBuilderForWindows("myCommand", "myArg1", "myArg2");
- * Map env = pb.environment();
- * env.put("VAR1", "myValue");
- * env.remove("OTHERVAR");
- * env.put("VAR2", env.get("VAR1") + "suffix");
- * pb.directory(new File("myDir"));
- * File log = new File("log");
- * pb.redirectErrorStream(true);
- * pb.redirectOutput(Redirect.appendTo(log));
- * Process p = pb.start();
- * assert pb.redirectInput() == Redirect.PIPE;
- * assert pb.redirectOutput().file() == log;
- * assert p.getInputStream().read() == -1;
- * }
- * - *

To start a process with an explicit set of environment - * variables, first call {@link Map#clear() Map.clear()} - * before adding environment variables. - * - * @author Martin Buchholz - * @since 1.5 - */ - -public class ProcessBuilderForWin32 { - - private String username; - private String password; - private List command; - private File directory; - private Map environment; - private boolean redirectErrorStream; - private ProcessBuilderForWin32.Redirect[] redirects; - - /** - * Constructs a process builder with the specified operating - * system program and arguments. This constructor does not - * make a copy of the {@code command} list. Subsequent - * updates to the list will be reflected in the state of the - * process builder. It is not checked whether - * {@code command} corresponds to a valid operating system - * command. - * - * @param command the list containing the program and its arguments - * @throws NullPointerException if the argument is null - */ - public ProcessBuilderForWin32(List command) { - if (command == null) { - throw new NullPointerException(); - } - this.command = command; - } - - /** - * Constructs a process builder with the specified operating - * system program and arguments. This is a convenience - * constructor that sets the process builder's command to a string - * list containing the same strings as the {@code command} - * array, in the same order. It is not checked whether - * {@code command} corresponds to a valid operating system - * command. - * - * @param command a string array containing the program and its arguments - */ - public ProcessBuilderForWin32(String... command) { - this.command = new ArrayList<>(command.length); - for (String arg : command) { - this.command.add(arg); - } - } - - /** - * set username and password for process - * - * @param username username - * @param password password - * @return this process builder - */ - public ProcessBuilderForWin32 user(String username, String password) { - this.username = username; - this.password = password; - return this; - } - - /** - * Sets this process builder's operating system program and - * arguments. This method does not make a copy of the - * {@code command} list. Subsequent updates to the list will - * be reflected in the state of the process builder. It is not - * checked whether {@code command} corresponds to a valid - * operating system command. - * - * @param command the list containing the program and its arguments - * @return this process builder - * - * @throws NullPointerException if the argument is null - */ - public ProcessBuilderForWin32 command(List command) { - if (command == null) { - throw new NullPointerException(); - } - this.command = command; - return this; - } - - /** - * Sets this process builder's operating system program and - * arguments. This is a convenience method that sets the command - * to a string list containing the same strings as the - * {@code command} array, in the same order. It is not - * checked whether {@code command} corresponds to a valid - * operating system command. - * - * @param command a string array containing the program and its arguments - * @return this process builder - */ - public ProcessBuilderForWin32 command(String... command) { - this.command = new ArrayList<>(command.length); - for (String arg : command) { - this.command.add(arg); - } - return this; - } - - /** - * Returns this process builder's operating system program and - * arguments. The returned list is not a copy. Subsequent - * updates to the list will be reflected in the state of this - * process builder. - * - * @return this process builder's program and its arguments - */ - public List command() { - return command; - } - - /** - * Returns a string map view of this process builder's environment. - * - * Whenever a process builder is created, the environment is - * initialized to a copy of the current process environment (see - * {@link System#getenv()}). Subprocesses subsequently started by - * this object's {@link #start()} method will use this map as - * their environment. - * - *

The returned object may be modified using ordinary {@link - * Map Map} operations. These modifications will be - * visible to subprocesses started via the {@link #start()} - * method. Two {@code ProcessBuilderForWindows} instances always - * contain independent process environments, so changes to the - * returned map will never be reflected in any other - * {@code ProcessBuilderForWindows} instance or the values returned by - * {@link System#getenv System.getenv}. - * - *

If the system does not support environment variables, an - * empty map is returned. - * - *

The returned map does not permit null keys or values. - * Attempting to insert or query the presence of a null key or - * value will throw a {@link NullPointerException}. - * Attempting to query the presence of a key or value which is not - * of type {@link String} will throw a {@link ClassCastException}. - * - *

The behavior of the returned map is system-dependent. A - * system may not allow modifications to environment variables or - * may forbid certain variable names or values. For this reason, - * attempts to modify the map may fail with - * {@link UnsupportedOperationException} or - * {@link IllegalArgumentException} - * if the modification is not permitted by the operating system. - * - *

Since the external format of environment variable names and - * values is system-dependent, there may not be a one-to-one - * mapping between them and Java's Unicode strings. Nevertheless, - * the map is implemented in such a way that environment variables - * which are not modified by Java code will have an unmodified - * native representation in the subprocess. - * - *

The returned map and its collection views may not obey the - * general contract of the {@link Object#equals} and - * {@link Object#hashCode} methods. - * - *

The returned map is typically case-sensitive on all platforms. - * - *

If a security manager exists, its - * {@link SecurityManager#checkPermission checkPermission} method - * is called with a - * {@link RuntimePermission}{@code ("getenv.*")} permission. - * This may result in a {@link SecurityException} being thrown. - * - *

When passing information to a Java subprocess, - * system properties - * are generally preferred over environment variables. - * - * @return this process builder's environment - * - * @throws SecurityException - * if a security manager exists and its - * {@link SecurityManager#checkPermission checkPermission} - * method doesn't allow access to the process environment - * - * @see Runtime#exec(String[],String[], File) - * @see System#getenv() - */ - public Map environment() { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkPermission(new RuntimePermission("getenv.*")); - } - - if (environment == null) { - environment = ProcessEnvironmentForWin32.environment(); - } - - assert environment != null; - - return environment; - } - - // Only for use by Runtime.exec(...envp...) - ProcessBuilderForWin32 environment(String[] envp) { - assert environment == null; - if (envp != null) { - environment = ProcessEnvironmentForWin32.emptyEnvironment(envp.length); - assert environment != null; - - for (String envstring : envp) { - // Before 1.5, we blindly passed invalid envstrings - // to the child process. - // We would like to throw an exception, but do not, - // for compatibility with old broken code. - - // Silently discard any trailing junk. - if (envstring.indexOf((int) '\u0000') != -1) { - envstring = envstring.replaceFirst("\u0000.*", ""); - } - - int eqlsign = - envstring.indexOf('=', ProcessEnvironmentForWin32.MIN_NAME_LENGTH); - // Silently ignore envstrings lacking the required `='. - if (eqlsign != -1) { - environment.put(envstring.substring(0,eqlsign), - envstring.substring(eqlsign+1)); - } - } - } - return this; - } - - /** - * Returns this process builder's working directory. - * - * Subprocesses subsequently started by this object's {@link - * #start()} method will use this as their working directory. - * The returned value may be {@code null} -- this means to use - * the working directory of the current Java process, usually the - * directory named by the system property {@code user.dir}, - * as the working directory of the child process. - * - * @return this process builder's working directory - */ - public File directory() { - return directory; - } - - /** - * Sets this process builder's working directory. - * - * Subprocesses subsequently started by this object's {@link - * #start()} method will use this as their working directory. - * The argument may be {@code null} -- this means to use the - * working directory of the current Java process, usually the - * directory named by the system property {@code user.dir}, - * as the working directory of the child process. - * - * @param directory the new working directory - * @return this process builder - */ - public ProcessBuilderForWin32 directory(File directory) { - this.directory = directory; - return this; - } - - // ---------------- I/O Redirection ---------------- - - /** - * Implements a null input stream. - */ - static class NullInputStream extends InputStream { - static final ProcessBuilderForWin32.NullInputStream INSTANCE = new ProcessBuilderForWin32.NullInputStream(); - private NullInputStream() {} - @Override - public int read() { return -1; } - @Override - public int available() { return 0; } - } - - /** - * Implements a null output stream. - */ - static class NullOutputStream extends OutputStream { - static final ProcessBuilderForWin32.NullOutputStream INSTANCE = new ProcessBuilderForWin32.NullOutputStream(); - private NullOutputStream() {} - @Override - public void write(int b) throws IOException { - throw new IOException("Stream closed"); - } - } - - /** - * Represents a source of subprocess input or a destination of - * subprocess output. - * - * Each {@code Redirect} instance is one of the following: - * - *

- * - *

Each of the above categories has an associated unique - * {@link ProcessBuilderForWin32.Redirect.Type Type}. - * - * @since 1.7 - */ - public abstract static class Redirect { - /** - * The type of a {@link ProcessBuilderForWin32.Redirect}. - */ - public enum Type { - /** - * The type of {@link ProcessBuilderForWin32.Redirect#PIPE Redirect.PIPE}. - */ - PIPE, - - /** - * The type of {@link ProcessBuilderForWin32.Redirect#INHERIT Redirect.INHERIT}. - */ - INHERIT, - - /** - * The type of redirects returned from - * {@link ProcessBuilderForWin32.Redirect#from Redirect.from(File)}. - */ - READ, - - /** - * The type of redirects returned from - * {@link ProcessBuilderForWin32.Redirect#to Redirect.to(File)}. - */ - WRITE, - - /** - * The type of redirects returned from - * {@link ProcessBuilderForWin32.Redirect#appendTo Redirect.appendTo(File)}. - */ - APPEND - } - - /** - * Returns the type of this {@code Redirect}. - * @return the type of this {@code Redirect} - */ - public abstract ProcessBuilderForWin32.Redirect.Type type(); - - /** - * Indicates that subprocess I/O will be connected to the - * current Java process over a pipe. - * - * This is the default handling of subprocess standard I/O. - * - *

It will always be true that - *

 {@code
-         * Redirect.PIPE.file() == null &&
-         * Redirect.PIPE.type() == Redirect.Type.PIPE
-         * }
- */ - public static final ProcessBuilderForWin32.Redirect PIPE = new ProcessBuilderForWin32.Redirect() { - @Override - public Type type() { return Type.PIPE; } - @Override - public String toString() { return type().toString(); }}; - - /** - * Indicates that subprocess I/O source or destination will be the - * same as those of the current process. This is the normal - * behavior of most operating system command interpreters (shells). - * - *

It will always be true that - *

 {@code
-         * Redirect.INHERIT.file() == null &&
-         * Redirect.INHERIT.type() == Redirect.Type.INHERIT
-         * }
- */ - public static final ProcessBuilderForWin32.Redirect INHERIT = new ProcessBuilderForWin32.Redirect() { - @Override - public Type type() { return Type.INHERIT; } - @Override - public String toString() { return type().toString(); }}; - - /** - * Returns the {@link File} source or destination associated - * with this redirect, or {@code null} if there is no such file. - * - * @return the file associated with this redirect, - * or {@code null} if there is no such file - */ - public File file() { return null; } - - /** - * When redirected to a destination file, indicates if the output - * is to be written to the end of the file. - */ - boolean append() { - throw new UnsupportedOperationException(); - } - - /** - * Returns a redirect to read from the specified file. - * - *

It will always be true that - *

 {@code
-         * Redirect.from(file).file() == file &&
-         * Redirect.from(file).type() == Redirect.Type.READ
-         * }
- * - * @param file The {@code File} for the {@code Redirect}. - * @throws NullPointerException if the specified file is null - * @return a redirect to read from the specified file - */ - public static ProcessBuilderForWin32.Redirect from(final File file) { - if (file == null) { - throw new NullPointerException(); - } - return new ProcessBuilderForWin32.Redirect() { - @Override - public Type type() { return Type.READ; } - @Override - public File file() { return file; } - @Override - public String toString() { - return "redirect to read from file \"" + file + "\""; - } - }; - } - - /** - * Returns a redirect to write to the specified file. - * If the specified file exists when the subprocess is started, - * its previous contents will be discarded. - * - *

It will always be true that - *

 {@code
-         * Redirect.to(file).file() == file &&
-         * Redirect.to(file).type() == Redirect.Type.WRITE
-         * }
- * - * @param file The {@code File} for the {@code Redirect}. - * @throws NullPointerException if the specified file is null - * @return a redirect to write to the specified file - */ - public static ProcessBuilderForWin32.Redirect to(final File file) { - if (file == null) { - throw new NullPointerException(); - } - return new ProcessBuilderForWin32.Redirect() { - @Override - public Type type() { return Type.WRITE; } - @Override - public File file() { return file; } - @Override - public String toString() { - return "redirect to write to file \"" + file + "\""; - } - @Override - boolean append() { return false; } - }; - } - - /** - * Returns a redirect to append to the specified file. - * Each write operation first advances the position to the - * end of the file and then writes the requested data. - * Whether the advancement of the position and the writing - * of the data are done in a single atomic operation is - * system-dependent and therefore unspecified. - * - *

It will always be true that - *

 {@code
-         * Redirect.appendTo(file).file() == file &&
-         * Redirect.appendTo(file).type() == Redirect.Type.APPEND
-         * }
- * - * @param file The {@code File} for the {@code Redirect}. - * @throws NullPointerException if the specified file is null - * @return a redirect to append to the specified file - */ - public static ProcessBuilderForWin32.Redirect appendTo(final File file) { - if (file == null) { - throw new NullPointerException(); - } - return new ProcessBuilderForWin32.Redirect() { - @Override - public Type type() { return Type.APPEND; } - @Override - public File file() { return file; } - @Override - public String toString() { - return "redirect to append to file \"" + file + "\""; - } - @Override - boolean append() { return true; } - }; - } - - /** - * Compares the specified object with this {@code Redirect} for - * equality. Returns {@code true} if and only if the two - * objects are identical or both objects are {@code Redirect} - * instances of the same type associated with non-null equal - * {@code File} instances. - */ - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (! (obj instanceof ProcessBuilderForWin32.Redirect)) { - return false; - } - ProcessBuilderForWin32.Redirect r = (ProcessBuilderForWin32.Redirect) obj; - if (r.type() != this.type()) { - return false; - } - assert this.file() != null; - return this.file().equals(r.file()); - } - - /** - * Returns a hash code value for this {@code Redirect}. - * @return a hash code value for this {@code Redirect} - */ - @Override - public int hashCode() { - File file = file(); - if (file == null) { - return super.hashCode(); - } else { - return file.hashCode(); - } - } - - /** - * No public constructors. Clients must use predefined - * static {@code Redirect} instances or factory methods. - */ - private Redirect() {} - } - - private ProcessBuilderForWin32.Redirect[] redirects() { - if (redirects == null) { - redirects = new Redirect[] { - Redirect.PIPE, Redirect.PIPE, Redirect.PIPE - }; - } - return redirects; - } - - /** - * Sets this process builder's standard input source. - * - * Subprocesses subsequently started by this object's {@link #start()} - * method obtain their standard input from this source. - * - *

If the source is {@link ProcessBuilderForWin32.Redirect#PIPE Redirect.PIPE} - * (the initial value), then the standard input of a - * subprocess can be written to using the output stream - * returned by {@link Process#getOutputStream()}. - * If the source is set to any other value, then - * {@link Process#getOutputStream()} will return a - * null output stream. - * - * @param source the new standard input source - * @return this process builder - * @throws IllegalArgumentException - * if the redirect does not correspond to a valid source - * of data, that is, has type - * {@link ProcessBuilderForWin32.Redirect.Type#WRITE WRITE} or - * {@link ProcessBuilderForWin32.Redirect.Type#APPEND APPEND} - * @since 1.7 - */ - public ProcessBuilderForWin32 redirectInput(ProcessBuilderForWin32.Redirect source) { - if (source.type() == ProcessBuilderForWin32.Redirect.Type.WRITE || - source.type() == ProcessBuilderForWin32.Redirect.Type.APPEND) { - throw new IllegalArgumentException( - "Redirect invalid for reading: " + source); - } - redirects()[0] = source; - return this; - } - - /** - * Sets this process builder's standard output destination. - * - * Subprocesses subsequently started by this object's {@link #start()} - * method send their standard output to this destination. - * - *

If the destination is {@link ProcessBuilderForWin32.Redirect#PIPE Redirect.PIPE} - * (the initial value), then the standard output of a subprocess - * can be read using the input stream returned by {@link - * Process#getInputStream()}. - * If the destination is set to any other value, then - * {@link Process#getInputStream()} will return a - * null input stream. - * - * @param destination the new standard output destination - * @return this process builder - * @throws IllegalArgumentException - * if the redirect does not correspond to a valid - * destination of data, that is, has type - * {@link ProcessBuilderForWin32.Redirect.Type#READ READ} - * @since 1.7 - */ - public ProcessBuilderForWin32 redirectOutput(ProcessBuilderForWin32.Redirect destination) { - if (destination.type() == ProcessBuilderForWin32.Redirect.Type.READ) { - throw new IllegalArgumentException( - "Redirect invalid for writing: " + destination); - } - redirects()[1] = destination; - return this; - } - - /** - * Sets this process builder's standard error destination. - * - * Subprocesses subsequently started by this object's {@link #start()} - * method send their standard error to this destination. - * - *

If the destination is {@link ProcessBuilderForWin32.Redirect#PIPE Redirect.PIPE} - * (the initial value), then the error output of a subprocess - * can be read using the input stream returned by {@link - * Process#getErrorStream()}. - * If the destination is set to any other value, then - * {@link Process#getErrorStream()} will return a - * null input stream. - * - *

If the {@link #redirectErrorStream redirectErrorStream} - * attribute has been set {@code true}, then the redirection set - * by this method has no effect. - * - * @param destination the new standard error destination - * @return this process builder - * @throws IllegalArgumentException - * if the redirect does not correspond to a valid - * destination of data, that is, has type - * {@link ProcessBuilderForWin32.Redirect.Type#READ READ} - * @since 1.7 - */ - public ProcessBuilderForWin32 redirectError(ProcessBuilderForWin32.Redirect destination) { - if (destination.type() == ProcessBuilderForWin32.Redirect.Type.READ) { - throw new IllegalArgumentException( - "Redirect invalid for writing: " + destination); - } - redirects()[2] = destination; - return this; - } - - /** - * Sets this process builder's standard input source to a file. - * - *

This is a convenience method. An invocation of the form - * {@code redirectInput(file)} - * behaves in exactly the same way as the invocation - * {@link #redirectInput(ProcessBuilderForWin32.Redirect) redirectInput} - * {@code (Redirect.from(file))}. - * - * @param file the new standard input source - * @return this process builder - * @since 1.7 - */ - public ProcessBuilderForWin32 redirectInput(File file) { - return redirectInput(ProcessBuilderForWin32.Redirect.from(file)); - } - - /** - * Sets this process builder's standard output destination to a file. - * - *

This is a convenience method. An invocation of the form - * {@code redirectOutput(file)} - * behaves in exactly the same way as the invocation - * {@link #redirectOutput(ProcessBuilderForWin32.Redirect) redirectOutput} - * {@code (Redirect.to(file))}. - * - * @param file the new standard output destination - * @return this process builder - * @since 1.7 - */ - public ProcessBuilderForWin32 redirectOutput(File file) { - return redirectOutput(ProcessBuilderForWin32.Redirect.to(file)); - } - - /** - * Sets this process builder's standard error destination to a file. - * - *

This is a convenience method. An invocation of the form - * {@code redirectError(file)} - * behaves in exactly the same way as the invocation - * {@link #redirectError(ProcessBuilderForWin32.Redirect) redirectError} - * {@code (Redirect.to(file))}. - * - * @param file the new standard error destination - * @return this process builder - * @since 1.7 - */ - public ProcessBuilderForWin32 redirectError(File file) { - return redirectError(ProcessBuilderForWin32.Redirect.to(file)); - } - - /** - * Returns this process builder's standard input source. - * - * Subprocesses subsequently started by this object's {@link #start()} - * method obtain their standard input from this source. - * The initial value is {@link ProcessBuilderForWin32.Redirect#PIPE Redirect.PIPE}. - * - * @return this process builder's standard input source - * @since 1.7 - */ - public ProcessBuilderForWin32.Redirect redirectInput() { - return (redirects == null) ? ProcessBuilderForWin32.Redirect.PIPE : redirects[0]; - } - - /** - * Returns this process builder's standard output destination. - * - * Subprocesses subsequently started by this object's {@link #start()} - * method redirect their standard output to this destination. - * The initial value is {@link ProcessBuilderForWin32.Redirect#PIPE Redirect.PIPE}. - * - * @return this process builder's standard output destination - * @since 1.7 - */ - public ProcessBuilderForWin32.Redirect redirectOutput() { - return (redirects == null) ? ProcessBuilderForWin32.Redirect.PIPE : redirects[1]; - } - - /** - * Returns this process builder's standard error destination. - * - * Subprocesses subsequently started by this object's {@link #start()} - * method redirect their standard error to this destination. - * The initial value is {@link ProcessBuilderForWin32.Redirect#PIPE Redirect.PIPE}. - * - * @return this process builder's standard error destination - * @since 1.7 - */ - public ProcessBuilderForWin32.Redirect redirectError() { - return (redirects == null) ? ProcessBuilderForWin32.Redirect.PIPE : redirects[2]; - } - - /** - * Sets the source and destination for subprocess standard I/O - * to be the same as those of the current Java process. - * - *

This is a convenience method. An invocation of the form - *

 {@code
-     * pb.inheritIO()
-     * }
- * behaves in exactly the same way as the invocation - *
 {@code
-     * pb.redirectInput(Redirect.INHERIT)
-     *   .redirectOutput(Redirect.INHERIT)
-     *   .redirectError(Redirect.INHERIT)
-     * }
- * - * This gives behavior equivalent to most operating system - * command interpreters, or the standard C library function - * {@code system()}. - * - * @return this process builder - * @since 1.7 - */ - public ProcessBuilderForWin32 inheritIO() { - Arrays.fill(redirects(), ProcessBuilderForWin32.Redirect.INHERIT); - return this; - } - - /** - * Tells whether this process builder merges standard error and - * standard output. - * - *

If this property is {@code true}, then any error output - * generated by subprocesses subsequently started by this object's - * {@link #start()} method will be merged with the standard - * output, so that both can be read using the - * {@link Process#getInputStream()} method. This makes it easier - * to correlate error messages with the corresponding output. - * The initial value is {@code false}. - * - * @return this process builder's {@code redirectErrorStream} property - */ - public boolean redirectErrorStream() { - return redirectErrorStream; - } - - /** - * Sets this process builder's {@code redirectErrorStream} property. - * - *

If this property is {@code true}, then any error output - * generated by subprocesses subsequently started by this object's - * {@link #start()} method will be merged with the standard - * output, so that both can be read using the - * {@link Process#getInputStream()} method. This makes it easier - * to correlate error messages with the corresponding output. - * The initial value is {@code false}. - * - * @param redirectErrorStream the new property value - * @return this process builder - */ - public ProcessBuilderForWin32 redirectErrorStream(boolean redirectErrorStream) { - this.redirectErrorStream = redirectErrorStream; - return this; - } - - /** - * Starts a new process using the attributes of this process builder. - * - *

The new process will - * invoke the command and arguments given by {@link #command()}, - * in a working directory as given by {@link #directory()}, - * with a process environment as given by {@link #environment()}. - * - *

This method checks that the command is a valid operating - * system command. Which commands are valid is system-dependent, - * but at the very least the command must be a non-empty list of - * non-null strings. - * - *

A minimal set of system dependent environment variables may - * be required to start a process on some operating systems. - * As a result, the subprocess may inherit additional environment variable - * settings beyond those in the process builder's {@link #environment()}. - * - *

If there is a security manager, its - * {@link SecurityManager#checkExec checkExec} - * method is called with the first component of this object's - * {@code command} array as its argument. This may result in - * a {@link SecurityException} being thrown. - * - *

Starting an operating system process is highly system-dependent. - * Among the many things that can go wrong are: - *

- * - *

In such cases an exception will be thrown. The exact nature - * of the exception is system-dependent, but it will always be a - * subclass of {@link IOException}. - * - *

Subsequent modifications to this process builder will not - * affect the returned {@link Process}. - * - * @return a new {@link Process} object for managing the subprocess - * - * @throws NullPointerException - * if an element of the command list is null - * - * @throws IndexOutOfBoundsException - * if the command is an empty list (has size {@code 0}) - * - * @throws SecurityException - * if a security manager exists and - *

- * - * @throws IOException if an I/O error occurs - * - * @see Runtime#exec(String[], String[], File) - */ - public Process start() throws IOException { - // Must convert to array first -- a malicious user-supplied - // list might try to circumvent the security check. - String[] cmdarray = command.toArray(new String[command.size()]); - cmdarray = cmdarray.clone(); - - for (String arg : cmdarray) { - if (arg == null) { - throw new NullPointerException(); - } - } - // Throws IndexOutOfBoundsException if command is empty - String prog = cmdarray[0]; - - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkExec(prog); - } - - String dir = directory == null ? null : directory.toString(); - - for (int i = 1; i < cmdarray.length; i++) { - if (cmdarray[i].indexOf('\u0000') >= 0) { - throw new IOException("invalid null character in command"); - } - } - - try { - return ProcessImplForWin32.start( - username, - password, - cmdarray, - environment, - dir, - redirects, - redirectErrorStream); - } catch (IOException | IllegalArgumentException e) { - String exceptionInfo = ": " + e.getMessage(); - Throwable cause = e; - if ((e instanceof IOException) && security != null) { - // Can not disclose the fail reason for read-protected files. - try { - security.checkRead(prog); - } catch (SecurityException se) { - exceptionInfo = ""; - cause = se; - } - } - // It's much easier for us to create a high-quality error - // message than the low-level C code which found the problem. - throw new IOException( - "Cannot run program \"" + prog + "\"" - + (dir == null ? "" : " (in directory \"" + dir + "\")") - + exceptionInfo, - cause); - } - } - -} diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/process/ProcessEnvironmentForWin32.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/process/ProcessEnvironmentForWin32.java deleted file mode 100644 index 85d9a2120c..0000000000 --- a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/process/ProcessEnvironmentForWin32.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.dolphinscheduler.common.utils.process; - -import com.sun.jna.platform.win32.Kernel32Util; - -import java.util.*; - -final class ProcessEnvironmentForWin32 extends HashMap { - - private static final long serialVersionUID = -8017839552603542824L; - - private static String validateName(String name) { - // An initial `=' indicates a magic Windows variable name -- OK - if (name.indexOf('=', 1) != -1 || - name.indexOf('\u0000') != -1) { - throw new IllegalArgumentException - ("Invalid environment variable name: \"" + name + "\""); - } - return name; - } - - private static String validateValue(String value) { - if (value.indexOf('\u0000') != -1) { - throw new IllegalArgumentException - ("Invalid environment variable value: \"" + value + "\""); - } - return value; - } - - private static String nonNullString(Object o) { - if (o == null) { - throw new NullPointerException(); - } - return (String) o; - } - - @Override - public String put(String key, String value) { - return super.put(validateName(key), validateValue(value)); - } - @Override - public String get(Object key) { - return super.get(nonNullString(key)); - } - @Override - public boolean containsKey(Object key) { - return super.containsKey(nonNullString(key)); - } - @Override - public boolean containsValue(Object value) { - return super.containsValue(nonNullString(value)); - } - @Override - public String remove(Object key) { - return super.remove(nonNullString(key)); - } - - private static class CheckedEntry implements Entry { - private final Entry e; - public CheckedEntry(Entry e) {this.e = e;} - @Override - public String getKey() { return e.getKey();} - @Override - public String getValue() { return e.getValue();} - @Override - public String setValue(String value) { - return e.setValue(validateValue(value)); - } - @Override - public String toString() { return getKey() + "=" + getValue();} - @Override - public boolean equals(Object o) {return e.equals(o);} - @Override - public int hashCode() {return e.hashCode();} - } - - private static class CheckedEntrySet extends AbstractSet> { - private final Set> s; - public CheckedEntrySet(Set> s) {this.s = s;} - @Override - public int size() {return s.size();} - @Override - public boolean isEmpty() {return s.isEmpty();} - @Override - public void clear() { s.clear();} - @Override - public Iterator> iterator() { - return new Iterator>() { - Iterator> i = s.iterator(); - @Override - public boolean hasNext() { return i.hasNext();} - @Override - public Entry next() { - return new CheckedEntry(i.next()); - } - @Override - public void remove() { i.remove();} - }; - } - private static Entry checkedEntry(Object o) { - @SuppressWarnings("unchecked") - Entry e = (Entry) o; - nonNullString(e.getKey()); - nonNullString(e.getValue()); - return e; - } - @Override - public boolean contains(Object o) {return s.contains(checkedEntry(o));} - @Override - public boolean remove(Object o) {return s.remove(checkedEntry(o));} - } - - private static class CheckedValues extends AbstractCollection { - private final Collection c; - public CheckedValues(Collection c) {this.c = c;} - @Override - public int size() {return c.size();} - @Override - public boolean isEmpty() {return c.isEmpty();} - @Override - public void clear() { c.clear();} - @Override - public Iterator iterator() {return c.iterator();} - @Override - public boolean contains(Object o) {return c.contains(nonNullString(o));} - @Override - public boolean remove(Object o) {return c.remove(nonNullString(o));} - } - - private static class CheckedKeySet extends AbstractSet { - private final Set s; - public CheckedKeySet(Set s) {this.s = s;} - @Override - public int size() {return s.size();} - @Override - public boolean isEmpty() {return s.isEmpty();} - @Override - public void clear() { s.clear();} - @Override - public Iterator iterator() {return s.iterator();} - @Override - public boolean contains(Object o) {return s.contains(nonNullString(o));} - @Override - public boolean remove(Object o) {return s.remove(nonNullString(o));} - } - @Override - public Set keySet() { - return new CheckedKeySet(super.keySet()); - } - @Override - public Collection values() { - return new CheckedValues(super.values()); - } - @Override - public Set> entrySet() { - return new CheckedEntrySet(super.entrySet()); - } - - private static final class NameComparator implements Comparator { - @Override - public int compare(String s1, String s2) { - // We can't use String.compareToIgnoreCase since it - // canonicalizes to lower case, while Windows - // canonicalizes to upper case! For example, "_" should - // sort *after* "Z", not before. - int n1 = s1.length(); - int n2 = s2.length(); - int min = Math.min(n1, n2); - for (int i = 0; i < min; i++) { - char c1 = s1.charAt(i); - char c2 = s2.charAt(i); - if (c1 != c2) { - c1 = Character.toUpperCase(c1); - c2 = Character.toUpperCase(c2); - if (c1 != c2) - // No overflow because of numeric promotion - { - return c1 - c2; - } - } - } - return n1 - n2; - } - } - - private static final class EntryComparator implements Comparator> { - @Override - public int compare(Entry e1, - Entry e2) { - return nameComparator.compare(e1.getKey(), e2.getKey()); - } - } - - // Allow `=' as first char in name, e.g. =C:=C:\DIR - static final int MIN_NAME_LENGTH = 1; - - private static final NameComparator nameComparator; - private static final EntryComparator entryComparator; - private static final ProcessEnvironmentForWin32 theEnvironment; - private static final Map theUnmodifiableEnvironment; - private static final Map theCaseInsensitiveEnvironment; - - static { - nameComparator = new NameComparator(); - entryComparator = new EntryComparator(); - theEnvironment = new ProcessEnvironmentForWin32(); - theUnmodifiableEnvironment = Collections.unmodifiableMap(theEnvironment); - - theEnvironment.putAll(environmentBlock()); - - theCaseInsensitiveEnvironment = new TreeMap<>(nameComparator); - theCaseInsensitiveEnvironment.putAll(theEnvironment); - } - - private ProcessEnvironmentForWin32() { - super(); - } - - private ProcessEnvironmentForWin32(int capacity) { - super(capacity); - } - - // Only for use by System.getenv(String) - static String getenv(String name) { - // The original implementation used a native call to _wgetenv, - // but it turns out that _wgetenv is only consistent with - // GetEnvironmentStringsW (for non-ASCII) if `wmain' is used - // instead of `main', even in a process created using - // CREATE_UNICODE_ENVIRONMENT. Instead we perform the - // case-insensitive comparison ourselves. At least this - // guarantees that System.getenv().get(String) will be - // consistent with System.getenv(String). - return theCaseInsensitiveEnvironment.get(name); - } - - // Only for use by System.getenv() - static Map getenv() { - return theUnmodifiableEnvironment; - } - - // Only for use by ProcessBuilder.environment() - @SuppressWarnings("unchecked") - static Map environment() { - return (Map) theEnvironment.clone(); - } - - // Only for use by ProcessBuilder.environment(String[] envp) - static Map emptyEnvironment(int capacity) { - return new ProcessEnvironmentForWin32(capacity); - } - - private static Map environmentBlock() { - return Kernel32Util.getEnvironmentVariables(); - } - - // Only for use by ProcessImpl.start() - String toEnvironmentBlock() { - // Sort Unicode-case-insensitively by name - List> list = new ArrayList<>(entrySet()); - Collections.sort(list, entryComparator); - - StringBuilder sb = new StringBuilder(size()*30); - int cmp = -1; - - // Some versions of MSVCRT.DLL require SystemRoot to be set. - // So, we make sure that it is always set, even if not provided - // by the caller. - final String SYSTEMROOT = "SystemRoot"; - - for (Entry e : list) { - String key = e.getKey(); - String value = e.getValue(); - if (cmp < 0 && (cmp = nameComparator.compare(key, SYSTEMROOT)) > 0) { - // Not set, so add it here - addToEnvIfSet(sb, SYSTEMROOT); - } - addToEnv(sb, key, value); - } - if (cmp < 0) { - // Got to end of list and still not found - addToEnvIfSet(sb, SYSTEMROOT); - } - if (sb.length() == 0) { - // Environment was empty and SystemRoot not set in parent - sb.append('\u0000'); - } - // Block is double NUL terminated - sb.append('\u0000'); - return sb.toString(); - } - - // add the environment variable to the child, if it exists in parent - private static void addToEnvIfSet(StringBuilder sb, String name) { - String s = getenv(name); - if (s != null) { - addToEnv(sb, name, s); - } - } - - private static void addToEnv(StringBuilder sb, String name, String val) { - sb.append(name).append('=').append(val).append('\u0000'); - } - - static String toEnvironmentBlock(Map map) { - return map == null ? null : ((ProcessEnvironmentForWin32)map).toEnvironmentBlock(); - } -} diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/process/ProcessImplForWin32.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/process/ProcessImplForWin32.java deleted file mode 100644 index 1efde52e62..0000000000 --- a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/utils/process/ProcessImplForWin32.java +++ /dev/null @@ -1,818 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -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.*; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Locale; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static com.sun.jna.platform.win32.WinBase.INVALID_HANDLE_VALUE; -import static com.sun.jna.platform.win32.WinBase.STILL_ACTIVE; -import static java.util.Objects.requireNonNull; - -public class ProcessImplForWin32 extends Process { - - 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; - - private static final int HANDLE_STORAGE_SIZE = 6; - - private static final int OFFSET_READ = 0; - - private static final int OFFSET_WRITE = 1; - - 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 - * with the resulting handle. This is because a FileOutputStream created - * to append to a file does not open the file in a manner that guarantees - * that writes by the child process will be atomic. - */ - private static FileOutputStream newFileOutputStream(File f, boolean append) - throws IOException - { - if (append) { - String path = f.getPath(); - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkWrite(path); - } - long handle = openForAtomicAppend(path); - final FileDescriptor fd = new FileDescriptor(); - setHandle(fd, handle); - return AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public FileOutputStream run() { - return new FileOutputStream(fd); - } - } - ); - } else { - return new FileOutputStream(f); - } - } - - // System-dependent portion of ProcessBuilderForWindows.start() - static Process start(String username, - String password, - String[] cmdarray, - java.util.Map environment, - String dir, - ProcessBuilderForWin32.Redirect[] redirects, - boolean redirectErrorStream) - throws IOException - { - String envblock = ProcessEnvironmentForWin32.toEnvironmentBlock(environment); - - FileInputStream f0 = null; - FileOutputStream f1 = null; - FileOutputStream f2 = null; - - try { - long[] stdHandles; - if (redirects == null) { - stdHandles = new long[] { -1L, -1L, -1L }; - } else { - stdHandles = new long[3]; - - if (redirects[0] == ProcessBuilderForWin32.Redirect.PIPE) { - stdHandles[0] = -1L; - } else if (redirects[0] == ProcessBuilderForWin32.Redirect.INHERIT) { - stdHandles[0] = getHandle(FileDescriptor.in); - } else { - f0 = new FileInputStream(redirects[0].file()); - stdHandles[0] = getHandle(f0.getFD()); - } - - if (redirects[1] == ProcessBuilderForWin32.Redirect.PIPE) { - stdHandles[1] = -1L; - } else if (redirects[1] == ProcessBuilderForWin32.Redirect.INHERIT) { - stdHandles[1] = getHandle(FileDescriptor.out); - } else { - f1 = newFileOutputStream(redirects[1].file(), - redirects[1].append()); - stdHandles[1] = getHandle(f1.getFD()); - } - - if (redirects[2] == ProcessBuilderForWin32.Redirect.PIPE) { - stdHandles[2] = -1L; - } else if (redirects[2] == ProcessBuilderForWin32.Redirect.INHERIT) { - stdHandles[2] = getHandle(FileDescriptor.err); - } else { - f2 = newFileOutputStream(redirects[2].file(), - redirects[2].append()); - stdHandles[2] = getHandle(f2.getFD()); - } - } - - return new ProcessImplForWin32(username, password, cmdarray, envblock, dir, stdHandles, redirectErrorStream); - } finally { - // In theory, close() can throw IOException - // (although it is rather unlikely to happen here) - try { if (f0 != null) { - f0.close(); - } - } - finally { - try { if (f1 != null) { - f1.close(); - } - } - finally { if (f2 != null) { - f2.close(); - } - } - } - } - - } - - private static class LazyPattern { - // Escape-support version: - // "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)" - private static final Pattern PATTERN = - Pattern.compile("[^\\s\"]+|\"[^\"]*\""); - } - - /* Parses the command string parameter into the executable name and - * program arguments. - * - * The command string is broken into tokens. The token separator is a space - * or quota character. The space inside quotation is not a token separator. - * There are no escape sequences. - */ - private static String[] getTokensFromCommand(String command) { - ArrayList matchList = new ArrayList<>(8); - Matcher regexMatcher = ProcessImplForWin32.LazyPattern.PATTERN.matcher(command); - while (regexMatcher.find()) { - matchList.add(regexMatcher.group()); - } - return matchList.toArray(new String[matchList.size()]); - } - - private static final int VERIFICATION_CMD_BAT = 0; - private static final int VERIFICATION_WIN32 = 1; - private static final int VERIFICATION_WIN32_SAFE = 2; // inside quotes not allowed - private static final int VERIFICATION_LEGACY = 3; - // See Command shell overview for documentation of special characters. - // https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490954(v=technet.10) - private static final char[][] ESCAPE_VERIFICATION = { - // We guarantee the only command file execution for implicit [cmd.exe] run. - // http://technet.microsoft.com/en-us/library/bb490954.aspx - {' ', '\t', '<', '>', '&', '|', '^'}, - {' ', '\t', '<', '>'}, - {' ', '\t', '<', '>'}, - {' ', '\t'} - }; - - private static String createCommandLine(int verificationType, - final String executablePath, - final String[] cmd) - { - StringBuilder cmdbuf = new StringBuilder(80); - - cmdbuf.append(executablePath); - - for (int i = 1; i < cmd.length; ++i) { - cmdbuf.append(' '); - String s = cmd[i]; - if (needsEscaping(verificationType, s)) { - cmdbuf.append('"'); - - if (verificationType == VERIFICATION_WIN32_SAFE) { - // Insert the argument, adding '\' to quote any interior quotes - int length = s.length(); - for (int j = 0; j < length; j++) { - char c = s.charAt(j); - if (c == DOUBLEQUOTE) { - int count = countLeadingBackslash(verificationType, s, j); - while (count-- > 0) { - cmdbuf.append(BACKSLASH); // double the number of backslashes - } - cmdbuf.append(BACKSLASH); // backslash to quote the quote - } - cmdbuf.append(c); - } - } else { - cmdbuf.append(s); - } - // The code protects the [java.exe] and console command line - // parser, that interprets the [\"] combination as an escape - // sequence for the ["] char. - // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx - // - // If the argument is an FS path, doubling of the tail [\] - // char is not a problem for non-console applications. - // - // The [\"] sequence is not an escape sequence for the [cmd.exe] - // command line parser. The case of the [""] tail escape - // sequence could not be realized due to the argument validation - // procedure. - int count = countLeadingBackslash(verificationType, s, s.length()); - while (count-- > 0) { - cmdbuf.append(BACKSLASH); // double the number of backslashes - } - cmdbuf.append('"'); - } else { - cmdbuf.append(s); - } - } - return cmdbuf.toString(); - } - - /** - * Return the argument without quotes (1st and last) if present, else the arg. - * @param str a string - * @return the string without 1st and last quotes - */ - private static String unQuote(String str) { - int len = str.length(); - return (len >= 2 && str.charAt(0) == DOUBLEQUOTE && str.charAt(len - 1) == DOUBLEQUOTE) - ? str.substring(1, len - 1) - : str; - } - - private static boolean needsEscaping(int verificationType, String arg) { - // Switch off MS heuristic for internal ["]. - // Please, use the explicit [cmd.exe] call - // if you need the internal ["]. - // Example: "cmd.exe", "/C", "Extended_MS_Syntax" - - // For [.exe] or [.com] file the unpaired/internal ["] - // in the argument is not a problem. - String unquotedArg = unQuote(arg); - boolean argIsQuoted = !arg.equals(unquotedArg); - boolean embeddedQuote = unquotedArg.indexOf(DOUBLEQUOTE) >= 0; - - switch (verificationType) { - case VERIFICATION_CMD_BAT: - if (embeddedQuote) { - throw new IllegalArgumentException("Argument has embedded quote, " + - "use the explicit CMD.EXE call."); - } - break; // break determine whether to quote - case VERIFICATION_WIN32_SAFE: - if (argIsQuoted && embeddedQuote) { - throw new IllegalArgumentException("Malformed argument has embedded quote: " - + unquotedArg); - } - break; - default: - break; - } - - if (!argIsQuoted) { - char[] testEscape = ESCAPE_VERIFICATION[verificationType]; - for (int i = 0; i < testEscape.length; ++i) { - if (arg.indexOf(testEscape[i]) >= 0) { - return true; - } - } - } - return false; - } - - private static String getExecutablePath(String path) - throws IOException - { - String name = unQuote(path); - if (name.indexOf(DOUBLEQUOTE) >= 0) { - throw new IllegalArgumentException("Executable name has embedded quote, " + - "split the arguments: " + name); - } - // Win32 CreateProcess requires path to be normalized - File fileToRun = new File(name); - - // From the [CreateProcess] function documentation: - // - // "If the file name does not contain an extension, .exe is appended. - // Therefore, if the file name extension is .com, this parameter - // must include the .com extension. If the file name ends in - // a period (.) with no extension, or if the file name contains a path, - // .exe is not appended." - // - // "If the file name !does not contain a directory path!, - // the system searches for the executable file in the following - // sequence:..." - // - // In practice ANY non-existent path is extended by [.exe] extension - // in the [CreateProcess] function with the only exception: - // the path ends by (.) - - return fileToRun.getPath(); - } - - /** - * An executable is any program that is an EXE or does not have an extension - * and the Windows createProcess will be looking for .exe. - * The comparison is case insensitive based on the name. - * @param executablePath the executable file - * @return true if the path ends in .exe or does not have an extension. - */ - private boolean isExe(String executablePath) { - File file = new File(executablePath); - String upName = file.getName().toUpperCase(Locale.ROOT); - return (upName.endsWith(".EXE") || upName.indexOf('.') < 0); - } - - // Old version that can be bypassed - private boolean isShellFile(String executablePath) { - String upPath = executablePath.toUpperCase(); - return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT")); - } - - private String quoteString(String arg) { - StringBuilder argbuf = new StringBuilder(arg.length() + 2); - return argbuf.append('"').append(arg).append('"').toString(); - } - - // Count backslashes before start index of string. - // .bat files don't include backslashes as part of the quote - private static int countLeadingBackslash(int verificationType, - CharSequence input, int start) { - if (verificationType == VERIFICATION_CMD_BAT) { - return 0; - } - int j; - for (j = start - 1; j >= 0 && input.charAt(j) == BACKSLASH; j--) { - // just scanning backwards - } - return (start - 1) - j; // number of BACKSLASHES - } - - private static final char DOUBLEQUOTE = '\"'; - private static final char BACKSLASH = '\\'; - - private WinNT.HANDLE handle; - private OutputStream stdinStream; - private InputStream stdoutStream; - private InputStream stderrStream; - - private ProcessImplForWin32( - String username, - String password, - String[] cmd, - final String envblock, - final String path, - final long[] stdHandles, - final boolean redirectErrorStream) - throws IOException - { - String cmdstr; - final SecurityManager security = System.getSecurityManager(); - GetPropertyAction action = new GetPropertyAction("jdk.lang.Process.allowAmbiguousCommands", - (security == null) ? "true" : "false"); - final boolean allowAmbiguousCommands = !"false".equalsIgnoreCase(action.run()); - if (allowAmbiguousCommands && security == null) { - // Legacy mode. - - // Normalize path if possible. - String executablePath = new File(cmd[0]).getPath(); - - // No worry about internal, unpaired ["], and redirection/piping. - if (needsEscaping(VERIFICATION_LEGACY, executablePath) ) { - executablePath = quoteString(executablePath); - } - - cmdstr = createCommandLine( - //legacy mode doesn't worry about extended verification - VERIFICATION_LEGACY, - executablePath, - cmd); - } else { - String executablePath; - try { - executablePath = getExecutablePath(cmd[0]); - } catch (IllegalArgumentException e) { - // Workaround for the calls like - // Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar") - - // No chance to avoid CMD/BAT injection, except to do the work - // right from the beginning. Otherwise we have too many corner - // cases from - // Runtime.getRuntime().exec(String[] cmd [, ...]) - // calls with internal ["] and escape sequences. - - // Restore original command line. - StringBuilder join = new StringBuilder(); - // terminal space in command line is ok - for (String s : cmd) { - join.append(s).append(' '); - } - - // Parse the command line again. - cmd = getTokensFromCommand(join.toString()); - executablePath = getExecutablePath(cmd[0]); - - // Check new executable name once more - if (security != null) { - security.checkExec(executablePath); - } - } - - // Quotation protects from interpretation of the [path] argument as - // start of longer path with spaces. Quotation has no influence to - // [.exe] extension heuristic. - boolean isShell = allowAmbiguousCommands ? isShellFile(executablePath) - : !isExe(executablePath); - cmdstr = createCommandLine( - // We need the extended verification procedures - isShell ? VERIFICATION_CMD_BAT - : (allowAmbiguousCommands ? VERIFICATION_WIN32 : VERIFICATION_WIN32_SAFE), - quoteString(executablePath), - cmd); - } - - handle = create(username, password, cmdstr, envblock, path, stdHandles, redirectErrorStream); - - AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public Void run() { - if (stdHandles[0] == -1L) { - stdinStream = ProcessBuilderForWin32.NullOutputStream.INSTANCE; - } else { - FileDescriptor stdinFd = new FileDescriptor(); - setHandle(stdinFd, stdHandles[0]); - stdinStream = new BufferedOutputStream( - new FileOutputStream(stdinFd)); - } - - if (stdHandles[1] == -1L) { - stdoutStream = ProcessBuilderForWin32.NullInputStream.INSTANCE; - } else { - FileDescriptor stdoutFd = new FileDescriptor(); - setHandle(stdoutFd, stdHandles[1]); - stdoutStream = new BufferedInputStream( - new FileInputStream(stdoutFd)); - } - - if (stdHandles[2] == -1L) { - stderrStream = ProcessBuilderForWin32.NullInputStream.INSTANCE; - } else { - FileDescriptor stderrFd = new FileDescriptor(); - setHandle(stderrFd, stdHandles[2]); - stderrStream = new FileInputStream(stderrFd); - } - - return null; }}); - } - - @Override - public OutputStream getOutputStream() { - return stdinStream; - } - - @Override - public InputStream getInputStream() { - return stdoutStream; - } - - @Override - public InputStream getErrorStream() { - return stderrStream; - } - - @Override - protected void finalize() { - closeHandle(handle); - } - - @Override - public int exitValue() { - int exitCode = getExitCodeProcess(handle); - if (exitCode == STILL_ACTIVE) { - throw new IllegalThreadStateException("process has not exited"); - } - return exitCode; - } - - @Override - public int waitFor() throws InterruptedException { - waitForInterruptibly(handle); - if (Thread.interrupted()) { - throw new InterruptedException(); - } - return exitValue(); - } - - @Override - public boolean waitFor(long timeout, TimeUnit unit) - throws InterruptedException - { - if (getExitCodeProcess(handle) != STILL_ACTIVE) { - return true; - } - if (timeout <= 0) { - return false; - } - - long remainingNanos = unit.toNanos(timeout); - long deadline = System.nanoTime() + remainingNanos ; - - do { - // Round up to next millisecond - long msTimeout = TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L); - waitForTimeoutInterruptibly(handle, msTimeout); - if (Thread.interrupted()) { - throw new InterruptedException(); - } - if (getExitCodeProcess(handle) != STILL_ACTIVE) { - return true; - } - remainingNanos = deadline - System.nanoTime(); - } while (remainingNanos > 0); - - return (getExitCodeProcess(handle) != STILL_ACTIVE); - } - - @Override - public void destroy() { terminateProcess(handle); } - - @Override - public Process destroyForcibly() { - destroy(); - return this; - } - @Override - public boolean isAlive() { - return isProcessAlive(handle); - } - - private static boolean initHolder(WinNT.HANDLEByReference pjhandles, - WinNT.HANDLEByReference[] pipe, - int offset, - WinNT.HANDLEByReference phStd) { - if (!pjhandles.getValue().equals(JAVA_INVALID_HANDLE_VALUE)) { - phStd.setValue(pjhandles.getValue()); - pjhandles.setValue(JAVA_INVALID_HANDLE_VALUE); - } else { - if (!Kernel32.INSTANCE.CreatePipe(pipe[0], pipe[1], null, PIPE_SIZE)) { - throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); - } else { - WinNT.HANDLE thisProcessEnd = offset == OFFSET_READ ? pipe[1].getValue() : pipe[0].getValue(); - phStd.setValue(pipe[offset].getValue()); - pjhandles.setValue(thisProcessEnd); - } - } - Kernel32.INSTANCE.SetHandleInformation(phStd.getValue(), WinBase.HANDLE_FLAG_INHERIT, WinBase.HANDLE_FLAG_INHERIT); - return true; - } - - private static void releaseHolder(boolean complete, WinNT.HANDLEByReference[] pipe, int offset) { - closeHandle(pipe[offset].getValue()); - if (complete) { - closeHandle(pipe[offset == OFFSET_READ ? OFFSET_WRITE : OFFSET_READ].getValue()); - } - } - - private static void prepareIOEHandleState(WinNT.HANDLE[] stdIOE, Boolean[] inherit) { - for(int i = 0; i < HANDLE_STORAGE_SIZE; ++i) { - WinNT.HANDLE hstd = stdIOE[i]; - if (!WinBase.INVALID_HANDLE_VALUE.equals(hstd)) { - inherit[i] = Boolean.TRUE; - Kernel32.INSTANCE.SetHandleInformation(hstd, WinBase.HANDLE_FLAG_INHERIT, 0); - } - } - } - - private static void restoreIOEHandleState(WinNT.HANDLE[] stdIOE, Boolean[] inherit) { - for (int i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i) { - if (!WinBase.INVALID_HANDLE_VALUE.equals(stdIOE[i])) { - Kernel32.INSTANCE.SetHandleInformation(stdIOE[i], WinBase.HANDLE_FLAG_INHERIT, Boolean.TRUE.equals(inherit[i]) ? WinBase.HANDLE_FLAG_INHERIT : 0); - } - } - } - - private static WinNT.HANDLE processCreate(String username, - String password, - String cmd, - final String envblock, - final String path, - final WinNT.HANDLEByReference[] stdHandles, - final boolean redirectErrorStream) { - WinNT.HANDLE ret = new WinNT.HANDLE(Pointer.createConstant(0)); - - WinNT.HANDLE[] stdIOE = new WinNT.HANDLE[] { - WinBase.INVALID_HANDLE_VALUE, WinBase.INVALID_HANDLE_VALUE, WinBase.INVALID_HANDLE_VALUE, - stdHandles[0].getValue(), stdHandles[1].getValue(), stdHandles[2].getValue() - }; - stdIOE[0] = Kernel32.INSTANCE.GetStdHandle(Wincon.STD_INPUT_HANDLE); - stdIOE[1] = Kernel32.INSTANCE.GetStdHandle(Wincon.STD_OUTPUT_HANDLE); - stdIOE[2] = Kernel32.INSTANCE.GetStdHandle(Wincon.STD_ERROR_HANDLE); - - Boolean[] inherit = new Boolean[] { - Boolean.FALSE, Boolean.FALSE, Boolean.FALSE, - Boolean.FALSE, Boolean.FALSE, Boolean.FALSE - }; - - prepareIOEHandleState(stdIOE, inherit); - - // input - WinNT.HANDLEByReference hStdInput = new WinNT.HANDLEByReference(); - WinNT.HANDLEByReference[] pipeIn = new WinNT.HANDLEByReference[] { - new WinNT.HANDLEByReference(WinBase.INVALID_HANDLE_VALUE), new WinNT.HANDLEByReference(WinBase.INVALID_HANDLE_VALUE) }; - - // output - WinNT.HANDLEByReference hStdOutput = new WinNT.HANDLEByReference(); - WinNT.HANDLEByReference[] pipeOut = new WinNT.HANDLEByReference[] { - new WinNT.HANDLEByReference(WinBase.INVALID_HANDLE_VALUE), new WinNT.HANDLEByReference(WinBase.INVALID_HANDLE_VALUE) }; - - // error - WinNT.HANDLEByReference hStdError = new WinNT.HANDLEByReference(); - WinNT.HANDLEByReference[] pipeError = new WinNT.HANDLEByReference[] { - new WinNT.HANDLEByReference(WinBase.INVALID_HANDLE_VALUE), new WinNT.HANDLEByReference(WinBase.INVALID_HANDLE_VALUE) }; - - boolean success; - if (initHolder(stdHandles[0], pipeIn, OFFSET_READ, hStdInput)) { - if (initHolder(stdHandles[1], pipeOut, OFFSET_WRITE, hStdOutput)) { - WinBase.STARTUPINFO si = new WinBase.STARTUPINFO(); - si.hStdInput = hStdInput.getValue(); - si.hStdOutput = hStdOutput.getValue(); - - if (redirectErrorStream) { - si.hStdError = si.hStdOutput; - stdHandles[2].setValue(JAVA_INVALID_HANDLE_VALUE); - success = true; - } else { - success = initHolder(stdHandles[2], pipeError, OFFSET_WRITE, hStdError); - si.hStdError = hStdError.getValue(); - } - - if (success) { - WTypes.LPSTR lpEnvironment = envblock == null ? new WTypes.LPSTR() : new WTypes.LPSTR(envblock); - WinBase.PROCESS_INFORMATION pi = new WinBase.PROCESS_INFORMATION(); - si.dwFlags = WinBase.STARTF_USESTDHANDLES; - if (!Advapi32.INSTANCE.CreateProcessWithLogonW( - username - , null - , password - , Advapi32.LOGON_WITH_PROFILE - , null - , cmd - , WinBase.CREATE_NO_WINDOW - , lpEnvironment.getPointer() - , path - , si - , pi)) { - throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); - } else { - closeHandle(pi.hThread); - ret = pi.hProcess; - } - } - releaseHolder(ret.getPointer().equals(Pointer.createConstant(0)), pipeError, OFFSET_WRITE); - releaseHolder(ret.getPointer().equals(Pointer.createConstant(0)), pipeOut, OFFSET_WRITE); - } - releaseHolder(ret.getPointer().equals(Pointer.createConstant(0)), pipeIn, OFFSET_READ); - } - restoreIOEHandleState(stdIOE, inherit); - return ret; - } - - private static synchronized WinNT.HANDLE create(String username, - String password, - String cmd, - final String envblock, - final String path, - final long[] stdHandles, - final boolean redirectErrorStream) { - WinNT.HANDLE ret = new WinNT.HANDLE(Pointer.createConstant(0)); - WinNT.HANDLEByReference[] handles = new WinNT.HANDLEByReference[stdHandles.length]; - for (int i = 0; i < stdHandles.length; i++) { - handles[i] = new WinNT.HANDLEByReference(new WinNT.HANDLE(Pointer.createConstant(stdHandles[i]))); - } - - if (cmd != null && username != null && password != null) { - ret = processCreate(username, password, cmd, envblock, path, handles, redirectErrorStream); - } - - for (int i = 0; i < stdHandles.length; i++) { - stdHandles[i] = handles[i].getPointer().getLong(0); - } - - return ret; - } - - private static int getExitCodeProcess(WinNT.HANDLE handle) { - IntByReference exitStatus = new IntByReference(); - if (!Kernel32.INSTANCE.GetExitCodeProcess(handle, exitStatus)) { - throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); - } - return exitStatus.getValue(); - } - - private static void terminateProcess(WinNT.HANDLE handle) { - Kernel32.INSTANCE.TerminateProcess(handle, 1); - } - - private static boolean isProcessAlive(WinNT.HANDLE handle) { - IntByReference exitStatus = new IntByReference(); - Kernel32.INSTANCE.GetExitCodeProcess(handle, exitStatus); - return exitStatus.getValue() == STILL_ACTIVE; - } - - private static void closeHandle(WinNT.HANDLE handle) { - if (!handle.equals(INVALID_HANDLE_VALUE)) { - Kernel32Util.closeHandle(handle); - } - } - - /** - * Opens a file for atomic append. The file is created if it doesn't - * already exist. - * - * @param path the file to open or create - * @return the native HANDLE - */ - private static long openForAtomicAppend(String path) throws IOException { - int access = WinNT.GENERIC_READ | WinNT.GENERIC_WRITE; - int sharing = WinNT.FILE_SHARE_READ | WinNT.FILE_SHARE_WRITE; - int disposition = WinNT.OPEN_ALWAYS; - int flagsAndAttributes = WinNT.FILE_ATTRIBUTE_NORMAL; - if (path == null || path.isEmpty()) { - return -1; - } else { - WinNT.HANDLE handle = Kernel32.INSTANCE.CreateFile(path, access, sharing, null, disposition, flagsAndAttributes, null); - if (handle == WinBase.INVALID_HANDLE_VALUE) { - throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); - } - return handle.getPointer().getLong(0); - } - } - - private static void waitForInterruptibly(WinNT.HANDLE handle) { - int result = Kernel32.INSTANCE.WaitForMultipleObjects(1, new WinNT.HANDLE[]{handle}, false, WinBase.INFINITE); - if (result == WinBase.WAIT_FAILED) { - throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); - } - } - - private static void waitForTimeoutInterruptibly(WinNT.HANDLE handle, long timeout) { - int result = Kernel32.INSTANCE.WaitForMultipleObjects(1, new WinNT.HANDLE[]{handle}, false, (int) timeout); - if (result == WinBase.WAIT_FAILED) { - throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); - } - } - -} diff --git a/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/process/ProcessBuilderForWin32Test.java b/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/process/ProcessBuilderForWin32Test.java deleted file mode 100644 index ce04346743..0000000000 --- a/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/process/ProcessBuilderForWin32Test.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.dolphinscheduler.common.utils.process; - -import org.apache.dolphinscheduler.common.utils.OSUtils; -import org.apache.dolphinscheduler.common.utils.StringUtils; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.*; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -@RunWith(PowerMockRunner.class) -@PrepareForTest(OSUtils.class) -public class ProcessBuilderForWin32Test { - - private static final Logger logger = LoggerFactory.getLogger(ProcessBuilderForWin32Test.class); - - @Before - public void before() { - PowerMockito.mockStatic(OSUtils.class); - PowerMockito.when(OSUtils.isWindows()).thenReturn(true); - } - - @Test - public void testCreateProcessBuilderForWin32() { - try { - ProcessBuilderForWin32 builder = new ProcessBuilderForWin32(); - Assert.assertNotNull(builder); - - builder = new ProcessBuilderForWin32("net"); - Assert.assertNotNull(builder); - - builder = new ProcessBuilderForWin32(Collections.singletonList("net")); - Assert.assertNotNull(builder); - - builder = new ProcessBuilderForWin32((List) null); - Assert.assertNotNull(builder); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testBuildUser() { - try { - ProcessBuilderForWin32 builder = new ProcessBuilderForWin32(); - builder.user("test", StringUtils.EMPTY); - Assert.assertNotNull(builder); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testBuildCommand() { - try { - ProcessBuilderForWin32 builder = new ProcessBuilderForWin32(); - builder.command(Collections.singletonList("net")); - Assert.assertNotEquals(0, builder.command().size()); - - builder = new ProcessBuilderForWin32(); - builder.command("net"); - Assert.assertNotEquals(0, builder.command().size()); - - builder = new ProcessBuilderForWin32(); - builder.command((List) null); - Assert.assertNotEquals(0, builder.command().size()); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testEnvironment() { - try { - ProcessBuilderForWin32 builder = new ProcessBuilderForWin32(); - Assert.assertNotNull(builder.environment()); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - - try { - ProcessBuilderForWin32 builder = new ProcessBuilderForWin32(); - builder.environment(new String[]{ "a=123" }); - Assert.assertNotEquals(0, builder.environment().size()); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testDirectory() { - try { - ProcessBuilderForWin32 builder = new ProcessBuilderForWin32(); - builder.directory(new File("/tmp")); - Assert.assertNotNull(builder.directory()); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testStream() { - try { - InputStream in = ProcessBuilderForWin32.NullInputStream.INSTANCE; - Assert.assertNotNull(in); - Assert.assertEquals(-1, in.read()); - Assert.assertEquals(0, in.available()); - - OutputStream out = ProcessBuilderForWin32.NullOutputStream.INSTANCE; - Assert.assertNotNull(out); - out.write(new byte[] {1}); - } catch (Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testRedirect() { - try { - ProcessBuilderForWin32 builder = new ProcessBuilderForWin32(); - - builder.redirectInput(new File("/tmp")); - Assert.assertNotNull(builder.redirectInput()); - Assert.assertNotNull(builder.redirectInput().file()); - - builder.redirectOutput(new File("/tmp")); - Assert.assertNotNull(builder.redirectOutput()); - Assert.assertNotNull(builder.redirectOutput().file()); - - builder.redirectError(new File("/tmp")); - Assert.assertNotNull(builder.redirectError()); - Assert.assertNotNull(builder.redirectError().file()); - - builder.redirectInput(builder.redirectOutput()); - builder.redirectOutput(builder.redirectInput()); - builder.redirectError(builder.redirectInput()); - - Assert.assertNotNull(ProcessBuilderForWin32.Redirect.PIPE.type()); - Assert.assertNotNull(ProcessBuilderForWin32.Redirect.PIPE.toString()); - Assert.assertNotNull(ProcessBuilderForWin32.Redirect.INHERIT.type()); - Assert.assertNotNull(ProcessBuilderForWin32.Redirect.INHERIT.toString()); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testRedirectErrorStream() { - try { - ProcessBuilderForWin32 builder = new ProcessBuilderForWin32(); - builder.redirectErrorStream(true); - Assert.assertTrue(builder.redirectErrorStream()); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void runCmdViaUser() { - try { - ProcessBuilderForWin32 builder = new ProcessBuilderForWin32(); - builder.user("test123", StringUtils.EMPTY); - - List commands = new ArrayList<>(); - commands.add("cmd.exe"); - commands.add("/c"); - commands.add("net user"); - builder.command(commands); - - Process process = builder.start(); - BufferedReader inReader = new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.forName("GBK"))); - String line; - StringBuilder sb = new StringBuilder(); - while ((line = inReader.readLine()) != null) { - sb.append(line); - } - logger.info("net user: {}", sb.toString()); - Assert.assertNotEquals(StringUtils.EMPTY, sb.toString()); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - -} diff --git a/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/process/ProcessEnvironmentForWin32Test.java b/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/process/ProcessEnvironmentForWin32Test.java deleted file mode 100644 index 00c54c0164..0000000000 --- a/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/process/ProcessEnvironmentForWin32Test.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.dolphinscheduler.common.utils.process; - -import org.apache.dolphinscheduler.common.utils.OSUtils; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({OSUtils.class, ProcessEnvironmentForWin32.class}) -public class ProcessEnvironmentForWin32Test { - - private static final Logger logger = LoggerFactory.getLogger(ProcessBuilderForWin32Test.class); - - @Before - public void before() { - try { - PowerMockito.mockStatic(OSUtils.class); - PowerMockito.when(OSUtils.isWindows()).thenReturn(true); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testPutAndGet() { - try { - ProcessEnvironmentForWin32 processEnvironmentForWin32 = (ProcessEnvironmentForWin32) ProcessEnvironmentForWin32.emptyEnvironment(0); - processEnvironmentForWin32.put("a", "123"); - Assert.assertEquals("123", processEnvironmentForWin32.get("a")); - Assert.assertTrue(processEnvironmentForWin32.containsKey("a")); - Assert.assertTrue(processEnvironmentForWin32.containsValue("123")); - Assert.assertEquals("123", processEnvironmentForWin32.remove("a")); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - - try { - ProcessEnvironmentForWin32 processEnvironmentForWin32 = (ProcessEnvironmentForWin32) ProcessEnvironmentForWin32.emptyEnvironment(0); - processEnvironmentForWin32.put("b=", "123"); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - - try { - ProcessEnvironmentForWin32 processEnvironmentForWin32 = (ProcessEnvironmentForWin32) ProcessEnvironmentForWin32.emptyEnvironment(0); - processEnvironmentForWin32.put("b", "\u0000"); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - - try { - ProcessEnvironmentForWin32 processEnvironmentForWin32 = (ProcessEnvironmentForWin32) ProcessEnvironmentForWin32.emptyEnvironment(0); - processEnvironmentForWin32.get(null); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testEntrySet() { - try { - ProcessEnvironmentForWin32 processEnvironmentForWin32 = (ProcessEnvironmentForWin32) ProcessEnvironmentForWin32.emptyEnvironment(0); - processEnvironmentForWin32.clear(); - processEnvironmentForWin32.put("a", "123"); - Assert.assertEquals(0, processEnvironmentForWin32.entrySet().size()); - Assert.assertTrue(processEnvironmentForWin32.entrySet().isEmpty()); - for (Map.Entry entry : processEnvironmentForWin32.entrySet()) { - Assert.assertNotNull(entry); - Assert.assertNotNull(entry.getKey()); - Assert.assertNotNull(entry.getValue()); - Assert.assertNotNull(entry.setValue("123")); - } - - processEnvironmentForWin32.clear(); - Set keys = processEnvironmentForWin32.keySet(); - Assert.assertEquals(0, keys.size()); - Assert.assertTrue(keys.isEmpty()); - - processEnvironmentForWin32.clear(); - Collection values = processEnvironmentForWin32.values(); - Assert.assertEquals(0, keys.size()); - Assert.assertTrue(keys.isEmpty()); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - - @Test - public void testToEnvironmentBlock() { - try { - ProcessEnvironmentForWin32 processEnvironmentForWin32 = (ProcessEnvironmentForWin32) ProcessEnvironmentForWin32.emptyEnvironment(0); - Assert.assertNotNull(processEnvironmentForWin32.toEnvironmentBlock()); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - -} diff --git a/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/process/ProcessImplForWin32Test.java b/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/process/ProcessImplForWin32Test.java deleted file mode 100644 index 3f8bcbfb66..0000000000 --- a/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/utils/process/ProcessImplForWin32Test.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.dolphinscheduler.common.utils.process; - -import org.apache.dolphinscheduler.common.utils.OSUtils; -import org.apache.dolphinscheduler.common.utils.StringUtils; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import sun.security.action.GetPropertyAction; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({OSUtils.class, GetPropertyAction.class}) -public class ProcessImplForWin32Test { - - private static final Logger logger = LoggerFactory.getLogger(ProcessBuilderForWin32Test.class); - - @Before - public void before() { - PowerMockito.mockStatic(OSUtils.class); - PowerMockito.mockStatic(GetPropertyAction.class); - PowerMockito.when(OSUtils.isWindows()).thenReturn(true); - } - - @Test - public void testStart() { - try { - Process process = ProcessImplForWin32.start( - "test123", StringUtils.EMPTY, new String[]{"net"}, - null, null, null, false); - Assert.assertNotNull(process); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - - try { - Process process = ProcessImplForWin32.start( - "test123", StringUtils.EMPTY, new String[]{"net"}, - null, null, new ProcessBuilderForWin32.Redirect[]{ - ProcessBuilderForWin32.Redirect.PIPE, - ProcessBuilderForWin32.Redirect.PIPE, - ProcessBuilderForWin32.Redirect.PIPE - }, false); - Assert.assertNotNull(process); - } catch (Error | Exception e) { - logger.error(e.getMessage()); - } - } - -} diff --git a/pom.xml b/pom.xml index c4f526cf21..a2a1ff7c5d 100644 --- a/pom.xml +++ b/pom.xml @@ -766,9 +766,6 @@ **/common/task/SqoopParameterEntityTest.java **/common/threadutils/ThreadPoolExecutorsTest.java **/common/threadutils/ThreadUtilsTest.java - **/common/utils/process/ProcessBuilderForWin32Test.java - **/common/utils/process/ProcessEnvironmentForWin32Test.java - **/common/utils/process/ProcessImplForWin32Test.java **/common/utils/CollectionUtilsTest.java **/common/utils/CommonUtilsTest.java **/common/utils/DateUtilsTest.java