3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.close;
19 |
20 | import java.io.IOException;
21 | import java.util.concurrent.Callable;
22 | import java.util.concurrent.ExecutionException;
23 | import java.util.concurrent.ExecutorService;
24 | import java.util.concurrent.Executors;
25 | import java.util.concurrent.Future;
26 | import java.util.concurrent.TimeUnit;
27 | import java.util.concurrent.TimeoutException;
28 |
29 | import org.slf4j.Logger;
30 | import org.slf4j.LoggerFactory;
31 | import org.zeroturnaround.exec.stream.ExecuteStreamHandler;
32 | import org.zeroturnaround.exec.stream.PumpStreamHandler;
33 |
34 | /**
35 | * Same as {@link StandardProcessCloser} but only waits fixed period for the closing.
36 | * On timeout a warning is logged but no error is thrown.
37 | *
38 | * This is used on Windows where sometimes sub process' streams do not close properly.
39 | */
40 | public class TimeoutProcessCloser extends StandardProcessCloser {
41 |
42 | private static final Logger log = LoggerFactory.getLogger(TimeoutProcessCloser.class);
43 |
44 | private final long timeout;
45 |
46 | private final TimeUnit unit;
47 |
48 | /**
49 | * Creates new instance of {@link TimeoutProcessCloser}.
50 | *
51 | * @param streams helper for pumping the streams.
52 | * @param timeout how long should we wait for the closing.
53 | * @param unit unit of the timeout value.
54 | */
55 | public TimeoutProcessCloser(ExecuteStreamHandler streams, long timeout, TimeUnit unit) {
56 | super(streams);
57 | this.timeout = timeout;
58 | this.unit = unit;
59 | }
60 |
61 | public void close(final Process process) throws IOException, InterruptedException {
62 | ExecutorService service = Executors.newSingleThreadScheduledExecutor();
63 | Future future = service.submit(new Callable() {
64 | public Void call() throws Exception {
65 | doClose(process);
66 | return null;
67 | }
68 | });
69 | // Previously submitted tasks are executed but no new tasks will be accepted.
70 | service.shutdown();
71 |
72 | try {
73 | future.get(timeout, unit);
74 | }
75 | catch (ExecutionException e) {
76 | throw new IllegalStateException("Could not close streams of " + process, e.getCause());
77 | }
78 | catch (TimeoutException e) {
79 | log.warn("Could not close streams of {} in {} {}", process, timeout, getUnitsAsString(timeout, unit));
80 | }
81 | finally {
82 | // Ensure that any data received so far is flushed from buffers
83 | if (streams instanceof PumpStreamHandler) {
84 | ((PumpStreamHandler) streams).flush();
85 | }
86 | }
87 | }
88 |
89 | protected void doClose(final Process process) throws IOException, InterruptedException {
90 | super.close(process);
91 | }
92 |
93 | private static String getUnitsAsString(long d, TimeUnit unit) {
94 | String result = unit.toString().toLowerCase();
95 | if (d == 1) {
96 | result = result.substring(0, result.length() - 1);
97 | }
98 | return result;
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/listener/CompositeProcessListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.listener;
19 |
20 | import java.util.Iterator;
21 | import java.util.List;
22 | import java.util.concurrent.CopyOnWriteArrayList;
23 |
24 | import org.zeroturnaround.exec.ProcessExecutor;
25 | import org.zeroturnaround.exec.ProcessResult;
26 |
27 |
28 | /**
29 | * Composite process event handler.
30 | *
31 | * @author Rein Raudjärv
32 | */
33 | public class CompositeProcessListener extends ProcessListener implements Cloneable {
34 |
35 | private final List children = new CopyOnWriteArrayList();
36 |
37 | public CompositeProcessListener() {
38 | // no children
39 | }
40 |
41 | public CompositeProcessListener(List children) {
42 | this.children.addAll(children);
43 | }
44 |
45 | /**
46 | * Add new listener.
47 | *
48 | * @param listener listener to be added.
49 | */
50 | public void add(ProcessListener listener) {
51 | children.add(listener);
52 | }
53 |
54 | /**
55 | * Remove existing listener.
56 | *
57 | * @param listener listener to be removed.
58 | */
59 | public void remove(ProcessListener listener) {
60 | children.remove(listener);
61 | }
62 |
63 | /**
64 | * Remove existing listeners of given type or its sub-types.
65 | *
66 | * @param type listener type.
67 | */
68 | public void removeAll(Class extends ProcessListener> type) {
69 | for (Iterator it = children.iterator(); it.hasNext();) {
70 | if (type.isInstance(it.next()))
71 | it.remove();
72 | }
73 | }
74 |
75 | /**
76 | * Remove all existing listeners.
77 | */
78 | public void clear() {
79 | children.clear();
80 | }
81 |
82 | public CompositeProcessListener clone() {
83 | return new CompositeProcessListener(children);
84 | }
85 |
86 | @Override
87 | public void beforeStart(ProcessExecutor executor) {
88 | for (ProcessListener child : children) {
89 | child.beforeStart(executor);
90 | }
91 | }
92 |
93 | @Override
94 | public void afterStart(Process process, ProcessExecutor executor) {
95 | for (ProcessListener child : children) {
96 | child.afterStart(process, executor);
97 | }
98 | }
99 |
100 | @Override
101 | public void afterFinish(Process process, ProcessResult result) {
102 | for (ProcessListener child : children) {
103 | child.afterFinish(process, result);
104 | }
105 | }
106 |
107 | @Override
108 | public void afterStop(Process process) {
109 | for (ProcessListener child : children) {
110 | child.afterStop(process);
111 | }
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/listener/DestroyerListenerAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.listener;
19 |
20 | import org.zeroturnaround.exec.ProcessExecutor;
21 |
22 | /**
23 | * Process event handler that wraps a process destroyer.
24 | *
25 | * @author Rein Raudjärv
26 | *
27 | * @see ProcessDestroyer
28 | */
29 | public class DestroyerListenerAdapter extends ProcessListener {
30 |
31 | private final ProcessDestroyer destroyer;
32 |
33 | public DestroyerListenerAdapter(ProcessDestroyer destroyer) {
34 | if (destroyer == null)
35 | throw new IllegalArgumentException("Process destroyer must be provided.");
36 | this.destroyer = destroyer;
37 | }
38 |
39 | @Override
40 | public void afterStart(Process process, ProcessExecutor executor) {
41 | destroyer.add(process);
42 | }
43 |
44 | @Override
45 | public void afterStop(Process process) {
46 | destroyer.remove(process);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/listener/ProcessDestroyer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * NOTICE: This file originates from the Apache Commons Exec package.
19 | * It has been modified to fit our needs.
20 | *
21 | * The following is the original header of the file in Apache Commons Exec:
22 | *
23 | * Licensed to the Apache Software Foundation (ASF) under one or more
24 | * contributor license agreements. See the NOTICE file distributed with
25 | * this work for additional information regarding copyright ownership.
26 | * The ASF licenses this file to You under the Apache License, Version 2.0
27 | * (the "License"); you may not use this file except in compliance with
28 | * the License. You may obtain a copy of the License at
29 | *
30 | * http://www.apache.org/licenses/LICENSE-2.0
31 | *
32 | * Unless required by applicable law or agreed to in writing, software
33 | * distributed under the License is distributed on an "AS IS" BASIS,
34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 | * See the License for the specific language governing permissions and
36 | * limitations under the License.
37 | */
38 | package org.zeroturnaround.exec.listener;
39 |
40 | /**
41 | * Destroys all registered {@link java.lang.Process} after a certain event,
42 | * typically when the VM exits
43 | * @see ShutdownHookProcessDestroyer
44 | */
45 | public interface ProcessDestroyer {
46 |
47 | /**
48 | * Returns true
if the specified
49 | * {@link java.lang.Process} was
50 | * successfully added to the list of processes to be destroy.
51 | *
52 | * @param process
53 | * the process to add
54 | * @return true
if the specified
55 | * {@link java.lang.Process} was
56 | * successfully added
57 | */
58 | boolean add(Process process);
59 |
60 | /**
61 | * Returns true
if the specified
62 | * {@link java.lang.Process} was
63 | * successfully removed from the list of processes to be destroy.
64 | *
65 | * @param process
66 | * the process to remove
67 | * @return true
if the specified
68 | * {@link java.lang.Process} was
69 | * successfully removed
70 | */
71 | boolean remove(Process process);
72 |
73 | /**
74 | * Returns the number of registered processes.
75 | *
76 | * @return the number of register process
77 | */
78 | int size();
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/listener/ProcessListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.listener;
19 |
20 | import org.zeroturnaround.exec.ProcessExecutor;
21 | import org.zeroturnaround.exec.ProcessResult;
22 |
23 | /**
24 | * Event handler for process events.
25 | *
26 | * This is a class instead of interface in order to add new methods without updating all implementations.
27 | *
28 | * @author Rein Raudjärv
29 | * @see ProcessExecutor#addListener(ProcessListener)
30 | */
31 | public abstract class ProcessListener {
32 |
33 | /**
34 | * Invoked before a process is started.
35 | *
36 | * @param executor executor used for starting a process.
37 | * Any changes made here apply to the starting process.
38 | * Once the process has started it is not affected by the {@link ProcessExecutor} any more.
39 | */
40 | public void beforeStart(ProcessExecutor executor) {
41 | // do nothing
42 | }
43 |
44 | /**
45 | * Invoked after a process has started.
46 | *
47 | * @param process the process started.
48 | * @param executor executor used for starting the process.
49 | * Modifying the {@link ProcessExecutor} only affects the following processes
50 | * not the one just started.
51 | */
52 | public void afterStart(Process process, ProcessExecutor executor) {
53 | // do nothing
54 | }
55 |
56 | /**
57 | * Invoked after a process has finished successfully.
58 | *
59 | * @param process process just finished.
60 | * @param result result of the finished process.
61 | * @since 1.8
62 | */
63 | public void afterFinish(Process process, ProcessResult result) {
64 | // do nothing
65 | }
66 |
67 | /**
68 | * Invoked after a process has exited (whether finished or cancelled).
69 | *
70 | * @param process process just stopped.
71 | */
72 | public void afterStop(Process process) {
73 | // do nothing
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/listener/ShutdownHookProcessDestroyer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * NOTICE: This file originates from the Apache Commons Exec package.
19 | * It has been modified to fit our needs.
20 | *
21 | * The following is the original header of the file in Apache Commons Exec:
22 | *
23 | * Licensed to the Apache Software Foundation (ASF) under one or more
24 | * contributor license agreements. See the NOTICE file distributed with
25 | * this work for additional information regarding copyright ownership.
26 | * The ASF licenses this file to You under the Apache License, Version 2.0
27 | * (the "License"); you may not use this file except in compliance with
28 | * the License. You may obtain a copy of the License at
29 | *
30 | * http://www.apache.org/licenses/LICENSE-2.0
31 | *
32 | * Unless required by applicable law or agreed to in writing, software
33 | * distributed under the License is distributed on an "AS IS" BASIS,
34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 | * See the License for the specific language governing permissions and
36 | * limitations under the License.
37 | */
38 | package org.zeroturnaround.exec.listener;
39 |
40 | import java.util.Enumeration;
41 | import java.util.Vector;
42 |
43 | import org.slf4j.Logger;
44 | import org.slf4j.LoggerFactory;
45 |
46 | /**
47 | * Destroys all registered Process
es when the VM exits.
48 | *
49 | * This class is copied from Commons Exec
.
50 | */
51 | public class ShutdownHookProcessDestroyer implements ProcessDestroyer, Runnable {
52 |
53 | private static final Logger log = LoggerFactory.getLogger(ShutdownHookProcessDestroyer.class);
54 |
55 | /**
56 | * Singleton instance of the {@link ShutdownHookProcessDestroyer}.
57 | */
58 | public static final ProcessDestroyer INSTANCE = new ShutdownHookProcessDestroyer();
59 |
60 | /** the list of currently running processes */
61 | private final Vector processes = new Vector();
62 |
63 | /** The thread registered at the JVM to execute the shutdown handler */
64 | private ProcessDestroyerImpl destroyProcessThread = null;
65 |
66 | /** Whether or not this ProcessDestroyer has been registered as a shutdown hook */
67 | private boolean added = false;
68 |
69 | /** Whether the shut down hook routine was already run **/
70 | private volatile boolean shutDownHookExecuted = false;
71 |
72 | /**
73 | * Whether or not this ProcessDestroyer is currently running as shutdown hook
74 | */
75 | private volatile boolean running = false;
76 |
77 | private class ProcessDestroyerImpl extends Thread {
78 |
79 | private boolean shouldDestroy = true;
80 |
81 | public ProcessDestroyerImpl() {
82 | super("ProcessDestroyer Shutdown Hook");
83 | }
84 |
85 | public void run() {
86 | if (shouldDestroy) {
87 | ShutdownHookProcessDestroyer.this.run();
88 | }
89 | }
90 |
91 | public void setShouldDestroy(final boolean shouldDestroy) {
92 | this.shouldDestroy = shouldDestroy;
93 | }
94 | }
95 |
96 | /**
97 | * Constructs a ProcessDestroyer
and obtains
98 | * Runtime.addShutdownHook()
and
99 | * Runtime.removeShutdownHook()
through reflection. The
100 | * ProcessDestroyer manages a list of processes to be destroyed when the VM
101 | * exits. If a process is added when the list is empty, this
102 | * ProcessDestroyer
is registered as a shutdown hook. If
103 | * removing a process results in an empty list, the
104 | * ProcessDestroyer
is removed as a shutdown hook.
105 | */
106 | public ShutdownHookProcessDestroyer() {
107 | }
108 |
109 | /**
110 | * Registers this ProcessDestroyer
as a shutdown hook, uses
111 | * reflection to ensure pre-JDK 1.3 compatibility.
112 | */
113 | private void addShutdownHook() {
114 | if (!running) {
115 | destroyProcessThread = new ProcessDestroyerImpl();
116 | Runtime.getRuntime().addShutdownHook(destroyProcessThread);
117 | added = true;
118 | }
119 | }
120 |
121 | /**
122 | * Removes this ProcessDestroyer
as a shutdown hook, uses
123 | * reflection to ensure pre-JDK 1.3 compatibility
124 | */
125 | private void removeShutdownHook() {
126 | if (added && !running) {
127 | boolean removed = Runtime.getRuntime().removeShutdownHook(
128 | destroyProcessThread);
129 | if (!removed) {
130 | log.error("Could not remove shutdown hook");
131 | }
132 | /*
133 | * start the hook thread, a unstarted thread may not be eligible for
134 | * garbage collection Cf.: http://developer.java.sun.com/developer/
135 | * bugParade/bugs/4533087.html
136 | */
137 |
138 | destroyProcessThread.setShouldDestroy(false);
139 | destroyProcessThread.start();
140 | // this should return quickly, since it basically is a NO-OP.
141 | try {
142 | destroyProcessThread.join(20000);
143 | }
144 | catch (InterruptedException ie) {
145 | // the thread didn't die in time
146 | // it should not kill any processes unexpectedly
147 | }
148 | destroyProcessThread = null;
149 | added = false;
150 | }
151 | }
152 |
153 | /**
154 | * Returns whether or not the ProcessDestroyer is registered as as shutdown
155 | * hook
156 | *
157 | * @return true if this is currently added as shutdown hook
158 | */
159 | public boolean isAddedAsShutdownHook() {
160 | return added;
161 | }
162 |
163 | /**
164 | * Returns true
if the specified Process
was
165 | * successfully added to the list of processes to destroy upon VM exit.
166 | *
167 | * @param process
168 | * the process to add
169 | * @return true
if the specified Process
was
170 | * successfully added
171 | */
172 | public boolean add(final Process process) {
173 | synchronized (processes) {
174 | // if this list is empty, register the shutdown hook
175 | if (processes.size() == 0) {
176 | try {
177 | if(shutDownHookExecuted) {
178 | throw new IllegalStateException();
179 | }
180 | addShutdownHook();
181 | }
182 | // kill the process now if the JVM is currently shutting down
183 | catch (IllegalStateException e) {
184 | destroy(process);
185 | }
186 | }
187 | processes.addElement(process);
188 | return processes.contains(process);
189 | }
190 | }
191 |
192 | /**
193 | * Returns true
if the specified Process
was
194 | * successfully removed from the list of processes to destroy upon VM exit.
195 | *
196 | * @param process
197 | * the process to remove
198 | * @return true
if the specified Process
was
199 | * successfully removed
200 | */
201 | public boolean remove(final Process process) {
202 | synchronized (processes) {
203 | boolean processRemoved = processes.removeElement(process);
204 | if (processRemoved && processes.size() == 0) {
205 | try {
206 | removeShutdownHook();
207 | } catch (IllegalStateException e) {
208 | /* if the JVM is shutting down, the hook cannot be removed */
209 | shutDownHookExecuted = true;
210 | }
211 | }
212 | return processRemoved;
213 | }
214 | }
215 |
216 | /**
217 | * Returns the number of registered processes.
218 | *
219 | * @return the number of register process
220 | */
221 | public int size() {
222 | return processes.size();
223 | }
224 |
225 | /**
226 | * Invoked by the VM when it is exiting.
227 | */
228 | public void run() {
229 | /* check if running the routine is still necessary */
230 | if(shutDownHookExecuted) {
231 | return;
232 | }
233 | synchronized (processes) {
234 | running = true;
235 | Enumeration e = processes.elements();
236 | while (e.hasMoreElements()) {
237 | destroy((Process) e.nextElement());
238 | }
239 | processes.clear();
240 | shutDownHookExecuted = true;
241 | }
242 | }
243 |
244 | private void destroy(Process process) {
245 | try {
246 | process.destroy();
247 | }
248 | catch (Throwable t) {
249 | log.error("Unable to terminate process during process shutdown");
250 | }
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stop/DestroyProcessStopper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stop;
19 |
20 | /**
21 | * Default {@link ProcessStopper} implementation that just invokes {@link Process#destroy()}.
22 | */
23 | public class DestroyProcessStopper implements ProcessStopper {
24 |
25 | /**
26 | * Singleton instance of the {@link DestroyProcessStopper}.
27 | */
28 | public static final ProcessStopper INSTANCE = new DestroyProcessStopper();
29 |
30 | public void stop(Process process) {
31 | process.destroy();
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stop/NopProcessStopper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stop;
19 |
20 | /**
21 | * {@link ProcessStopper} implementation that does nothing - it keeps the process running.
22 | */
23 | public class NopProcessStopper implements ProcessStopper {
24 |
25 | /**
26 | * Singleton instance of the {@link NopProcessStopper}.
27 | */
28 | public static final ProcessStopper INSTANCE = new NopProcessStopper();
29 |
30 | public void stop(Process process) {
31 | // don't stop the process
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stop/ProcessStopper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stop;
19 |
20 | import java.util.concurrent.Future;
21 |
22 | /**
23 | * Abstraction for stopping sub processes.
24 | *
25 | * This is used in case a process runs too long (timeout is reached) or it's cancelled via {@link Future#cancel(boolean)}.
26 | */
27 | public interface ProcessStopper {
28 |
29 | /**
30 | * Stops a given sub process.
31 | * It does not wait for the process to actually stop and it has no guarantee that the process terminates.
32 | *
33 | * @param process sub process being stopped (not null
).
34 | */
35 | void stop(Process process);
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/CallerLoggerUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stream;
19 |
20 | /**
21 | * Constructs name for the caller logger.
22 | *
23 | * @author Rein Raudjärv
24 | */
25 | public abstract class CallerLoggerUtil {
26 |
27 | /**
28 | * Returns full name for the caller class' logger.
29 | *
30 | * @param name name of the logger. In case of full name (it contains dots) same value is just returned.
31 | * In case of short names (no dots) the given name is prefixed by caller's class name and a dot.
32 | * In case of null
the caller's class name is just returned.
33 | * @return full name for the caller class' logger.
34 | */
35 | public static String getName(String name) {
36 | return getName(name, 1);
37 | }
38 |
39 | /**
40 | * Returns full name for the caller class' logger.
41 | *
42 | * @param name name of the logger. In case of full name (it contains dots) same value is just returned.
43 | * In case of short names (no dots) the given name is prefixed by caller's class name and a dot.
44 | * In case of null
the caller's class name is just returned.
45 | * @param level no of call stack levels to get the caller (0 means the caller of this method).
46 | * @return full name for the caller class' logger.
47 | */
48 | public static String getName(String name, int level) {
49 | level++;
50 | String fullName;
51 | if (name == null)
52 | fullName = getCallerClassName(level);
53 | else if (name.contains("."))
54 | fullName = name;
55 | else
56 | fullName = getCallerClassName(level) + "." + name;
57 | return fullName;
58 | }
59 |
60 | /**
61 | * @return caller class name of the given level.
62 | */
63 | private static String getCallerClassName(int level) {
64 | return Thread.currentThread().getStackTrace()[level + 2].getClassName();
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/ExecuteStreamHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * NOTICE: This file originates from the Apache Commons Exec package.
19 | * It has been modified to fit our needs.
20 | *
21 | * The following is the original header of the file in Apache Commons Exec:
22 | *
23 | * Licensed to the Apache Software Foundation (ASF) under one or more
24 | * contributor license agreements. See the NOTICE file distributed with
25 | * this work for additional information regarding copyright ownership.
26 | * The ASF licenses this file to You under the Apache License, Version 2.0
27 | * (the "License"); you may not use this file except in compliance with
28 | * the License. You may obtain a copy of the License at
29 | *
30 | * http://www.apache.org/licenses/LICENSE-2.0
31 | *
32 | * Unless required by applicable law or agreed to in writing, software
33 | * distributed under the License is distributed on an "AS IS" BASIS,
34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 | * See the License for the specific language governing permissions and
36 | * limitations under the License.
37 | */
38 | package org.zeroturnaround.exec.stream;
39 |
40 | import java.io.IOException;
41 | import java.io.InputStream;
42 | import java.io.OutputStream;
43 |
44 | /**
45 | * Used by Execute
to handle input and output stream of
46 | * subprocesses.
47 | */
48 | public interface ExecuteStreamHandler {
49 |
50 | /**
51 | * Install a handler for the input stream of the subprocess.
52 | *
53 | * @param os
54 | * output stream to write to the standard input stream of the
55 | * subprocess
56 | * @throws IOException throws a IO exception in case of IO issues of the underlying stream
57 | */
58 | void setProcessInputStream(OutputStream os) throws IOException;
59 |
60 | /**
61 | * Install a handler for the error stream of the subprocess.
62 | *
63 | * @param is
64 | * input stream to read from the error stream from the subprocess
65 | * @throws IOException throws a IO exception in case of IO issues of the underlying stream
66 | */
67 | void setProcessErrorStream(InputStream is) throws IOException;
68 |
69 | /**
70 | * Install a handler for the output stream of the subprocess.
71 | *
72 | * @param is
73 | * input stream to read from the error stream from the subprocess
74 | * @throws IOException throws a IO exception in case of IO issues of the underlying stream
75 | */
76 | void setProcessOutputStream(InputStream is) throws IOException;
77 |
78 | /**
79 | * Start handling of the streams.
80 | *
81 | * @throws IOException throws a IO exception in case of IO issues of the underlying stream
82 | */
83 | void start() throws IOException;
84 |
85 | /**
86 | * Stop handling of the streams - will not be restarted.
87 | * Will wait for pump threads to complete.
88 | */
89 | void stop();
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/InputStreamPumper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * NOTICE: This file originates from the Apache Commons Exec package.
19 | * It has been modified to fit our needs.
20 | *
21 | * The following is the original header of the file in Apache Commons Exec:
22 | *
23 | * Licensed to the Apache Software Foundation (ASF) under one or more
24 | * contributor license agreements. See the NOTICE file distributed with
25 | * this work for additional information regarding copyright ownership.
26 | * The ASF licenses this file to You under the Apache License, Version 2.0
27 | * (the "License"); you may not use this file except in compliance with
28 | * the License. You may obtain a copy of the License at
29 | *
30 | * http://www.apache.org/licenses/LICENSE-2.0
31 | *
32 | * Unless required by applicable law or agreed to in writing, software
33 | * distributed under the License is distributed on an "AS IS" BASIS,
34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 | * See the License for the specific language governing permissions and
36 | * limitations under the License.
37 | */
38 | package org.zeroturnaround.exec.stream;
39 |
40 | import java.io.InputStream;
41 | import java.io.OutputStream;
42 |
43 | import org.slf4j.Logger;
44 | import org.slf4j.LoggerFactory;
45 |
46 | /**
47 | * Copies all data from an System.input stream to an output stream of the executed process.
48 | *
49 | * @author mkleint
50 | */
51 | public class InputStreamPumper implements Runnable {
52 |
53 | private static final Logger log = LoggerFactory.getLogger(InputStreamPumper.class);
54 |
55 | public static final int SLEEPING_TIME = 100;
56 |
57 | /** the input stream to pump from */
58 | private final InputStream is;
59 |
60 | /** the output stream to pmp into */
61 | private final OutputStream os;
62 |
63 | /** flag to stop the stream pumping */
64 | private volatile boolean stop;
65 |
66 | /**
67 | * Create a new stream pumper.
68 | *
69 | * @param is input stream to read data from
70 | * @param os output stream to write data to.
71 | */
72 | public InputStreamPumper(final InputStream is, final OutputStream os) {
73 | this.is = is;
74 | this.os = os;
75 | this.stop = false;
76 | }
77 |
78 | /**
79 | * Copies data from the input stream to the output stream. Terminates as
80 | * soon as the input stream is closed or an error occurs.
81 | */
82 | public void run() {
83 | try {
84 | while (!stop) {
85 | while (is.available() > 0 && !stop) {
86 | os.write(is.read());
87 | }
88 | os.flush();
89 | Thread.sleep(SLEEPING_TIME);
90 | }
91 | }
92 | catch (Exception e) {
93 | log.error("Got exception while reading/writing the stream", e);
94 | }
95 | }
96 |
97 | public void stopProcessing() {
98 | stop = true;
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/LineConsumer.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.stream;
2 |
3 | /**
4 | * This is equivalent to {@code java.util.function.Consumer} while staying compatible with
5 | * Java versions earlier than 8.
6 | */
7 | public interface LineConsumer {
8 | void accept(String line);
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/LogOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stream;
19 |
20 | import java.io.ByteArrayOutputStream;
21 | import java.io.IOException;
22 | import java.io.OutputStream;
23 | import java.io.UnsupportedEncodingException;
24 |
25 | /**
26 | * Base class to connect a logging system to the output and/or
27 | * error stream of then external process. The implementation
28 | * parses the incoming data to construct a line and passes
29 | * the complete line to an user-defined implementation.
30 | */
31 | public abstract class LogOutputStream extends OutputStream {
32 |
33 | /** Initial buffer size. */
34 | private static final int INITIAL_SIZE = 132;
35 |
36 | /** Carriage return */
37 | private static final int CR = 0x0d;
38 |
39 | /** Linefeed */
40 | private static final int LF = 0x0a;
41 |
42 | /** the internal buffer */
43 | private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(
44 | INITIAL_SIZE);
45 |
46 | byte lastReceivedByte;
47 |
48 | private String outputCharset;
49 |
50 | public LogOutputStream setOutputCharset(final String outputCharset) {
51 | this.outputCharset = outputCharset;
52 | return this;
53 | }
54 |
55 | /**
56 | * Write the data to the buffer and flush the buffer, if a line separator is
57 | * detected.
58 | *
59 | * @param cc data to log (byte).
60 | * @see java.io.OutputStream#write(int)
61 | */
62 | public void write(final int cc) throws IOException {
63 | final byte c = (byte) cc;
64 | if ((c == '\n') || (c == '\r')) {
65 | // new line is started in case of
66 | // - CR (regardless of previous character)
67 | // - LF if previous character was not CR and not LF
68 | if (c == '\r' || (c == '\n' && (lastReceivedByte != '\r' && lastReceivedByte != '\n'))) {
69 | processBuffer();
70 | }
71 | } else {
72 | buffer.write(cc);
73 | }
74 | lastReceivedByte = c;
75 | }
76 |
77 | /**
78 | * Flush this log stream.
79 | *
80 | * @see java.io.OutputStream#flush()
81 | */
82 | public void flush() {
83 | if (buffer.size() > 0) {
84 | processBuffer();
85 | }
86 | }
87 |
88 | /**
89 | * Writes all remaining data from the buffer.
90 | *
91 | * @see java.io.OutputStream#close()
92 | */
93 | public void close() throws IOException {
94 | if (buffer.size() > 0) {
95 | processBuffer();
96 | }
97 | super.close();
98 | }
99 |
100 | /**
101 | * Write a block of characters to the output stream
102 | *
103 | * @param b the array containing the data
104 | * @param off the offset into the array where data starts
105 | * @param len the length of block
106 | * @throws java.io.IOException if the data cannot be written into the stream.
107 | * @see java.io.OutputStream#write(byte[], int, int)
108 | */
109 | public void write(final byte[] b, final int off, final int len)
110 | throws IOException {
111 | // find the line breaks and pass other chars through in blocks
112 | int offset = off;
113 | int blockStartOffset = offset;
114 | int remaining = len;
115 | while (remaining > 0) {
116 | while (remaining > 0 && b[offset] != LF && b[offset] != CR) {
117 | offset++;
118 | remaining--;
119 | }
120 | // either end of buffer or a line separator char
121 | int blockLength = offset - blockStartOffset;
122 | if (blockLength > 0) {
123 | buffer.write(b, blockStartOffset, blockLength);
124 | lastReceivedByte = 0;
125 | }
126 | while (remaining > 0 && (b[offset] == LF || b[offset] == CR)) {
127 | write(b[offset]);
128 | offset++;
129 | remaining--;
130 | }
131 | blockStartOffset = offset;
132 | }
133 | }
134 |
135 | /**
136 | * Converts the buffer to a string and sends it to processLine
.
137 | */
138 | protected void processBuffer() {
139 | final String line;
140 | if (outputCharset == null) {
141 | line = buffer.toString();
142 | } else {
143 | try {
144 | line = buffer.toString(outputCharset);
145 | } catch (UnsupportedEncodingException e) {
146 | throw new IllegalArgumentException(e);
147 | }
148 | }
149 | processLine(line);
150 | buffer.reset();
151 | }
152 |
153 | /**
154 | * Logs a line to the log system of the user.
155 | *
156 | * @param line
157 | * the line to log.
158 | */
159 | protected abstract void processLine(String line);
160 |
161 | /**
162 | * Factory method to create a LogOutputStream
that passes each line to the specified consumer.
163 | * Mostly useful with Java 8+, so the consumer can be passed as a lambda expression.
164 | *
165 | * @param consumer the consumer to consume the log lines
166 | * @return the created LogOutputStream
, passing each line to the specified consumer.
167 | */
168 | public static LogOutputStream create(final LineConsumer consumer) {
169 | if (consumer == null) {
170 | throw new IllegalArgumentException("Line consumer must be provided.");
171 | }
172 | return new LogOutputStream() {
173 | @Override
174 | protected void processLine(String line) {
175 | consumer.accept(line);
176 | }
177 | };
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/NullOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Ketan Padegaonkar
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.zeroturnaround.exec.stream;
18 |
19 | import java.io.IOException;
20 | import java.io.OutputStream;
21 |
22 | /**
23 | * An OutputStream which ignores everything written to it.
24 | */
25 | public class NullOutputStream extends OutputStream {
26 |
27 | /**
28 | * A singleton.
29 | */
30 | public static final NullOutputStream NULL_OUTPUT_STREAM = new NullOutputStream();
31 |
32 | public void write(byte[] b, int off, int len) {
33 | // discard!
34 | }
35 |
36 | public void write(int b) {
37 | // discard!
38 | }
39 |
40 | public void write(byte[] b) throws IOException {
41 | // discard!
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/StreamPumper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * NOTICE: This file originates from the Apache Commons Exec package.
19 | * It has been modified to fit our needs.
20 | *
21 | * The following is the original header of the file in Apache Commons Exec:
22 | *
23 | * Licensed to the Apache Software Foundation (ASF) under one or more
24 | * contributor license agreements. See the NOTICE file distributed with
25 | * this work for additional information regarding copyright ownership.
26 | * The ASF licenses this file to You under the Apache License, Version 2.0
27 | * (the "License"); you may not use this file except in compliance with
28 | * the License. You may obtain a copy of the License at
29 | *
30 | * http://www.apache.org/licenses/LICENSE-2.0
31 | *
32 | * Unless required by applicable law or agreed to in writing, software
33 | * distributed under the License is distributed on an "AS IS" BASIS,
34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 | * See the License for the specific language governing permissions and
36 | * limitations under the License.
37 | */
38 | package org.zeroturnaround.exec.stream;
39 |
40 | import java.io.IOException;
41 | import java.io.InputStream;
42 | import java.io.OutputStream;
43 |
44 | import org.slf4j.Logger;
45 | import org.slf4j.LoggerFactory;
46 |
47 | /**
48 | * Copies all data from an input stream to an output stream.
49 | */
50 | public class StreamPumper implements Runnable {
51 |
52 | private static final Logger log = LoggerFactory.getLogger(StreamPumper.class);
53 |
54 | /** the default size of the internal buffer for copying the streams */
55 | private static final int DEFAULT_SIZE = 1024;
56 |
57 | /** the input stream to pump from */
58 | private final InputStream is;
59 |
60 | /** the output stream to pmp into */
61 | private final OutputStream os;
62 |
63 | /** the size of the internal buffer for copying the streams */
64 | private final int size;
65 |
66 | /** was the end of the stream reached */
67 | private boolean finished;
68 |
69 | /** close the output stream when exhausted */
70 | private final boolean closeWhenExhausted;
71 |
72 | /** flush the output stream after each write */
73 | private final boolean flushImmediately;
74 |
75 | /**
76 | * Create a new stream pumper.
77 | *
78 | * @param is input stream to read data from
79 | * @param os output stream to write data to.
80 | * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
81 | * @param flushImmediately flush the output stream whenever data was written to it
82 | */
83 | public StreamPumper(final InputStream is, final OutputStream os,
84 | final boolean closeWhenExhausted, boolean flushImmediately) {
85 | this.is = is;
86 | this.os = os;
87 | this.size = DEFAULT_SIZE;
88 | this.closeWhenExhausted = closeWhenExhausted;
89 | this.flushImmediately = flushImmediately;
90 | }
91 |
92 | /**
93 | * Create a new stream pumper.
94 | *
95 | * @param is input stream to read data from
96 | * @param os output stream to write data to.
97 | * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
98 | * @param size the size of the internal buffer for copying the streams
99 | * @param flushImmediately flush the output stream whenever data was written to it
100 | */
101 | public StreamPumper(final InputStream is, final OutputStream os,
102 | final boolean closeWhenExhausted, final int size, boolean flushImmediately) {
103 | this.is = is;
104 | this.os = os;
105 | this.size = (size > 0 ? size : DEFAULT_SIZE);
106 | this.closeWhenExhausted = closeWhenExhausted;
107 | this.flushImmediately = flushImmediately;
108 | }
109 |
110 | /**
111 | * Create a new stream pumper.
112 | *
113 | * @param is input stream to read data from
114 | * @param os output stream to write data to.
115 | * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
116 | */
117 | public StreamPumper(final InputStream is, final OutputStream os,
118 | final boolean closeWhenExhausted) {
119 | this.is = is;
120 | this.os = os;
121 | this.size = DEFAULT_SIZE;
122 | this.closeWhenExhausted = closeWhenExhausted;
123 | this.flushImmediately = false;
124 | }
125 |
126 | /**
127 | * Create a new stream pumper.
128 | *
129 | * @param is input stream to read data from
130 | * @param os output stream to write data to.
131 | * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
132 | * @param size the size of the internal buffer for copying the streams
133 | */
134 | public StreamPumper(final InputStream is, final OutputStream os,
135 | final boolean closeWhenExhausted, final int size) {
136 | this.is = is;
137 | this.os = os;
138 | this.size = (size > 0 ? size : DEFAULT_SIZE);
139 | this.closeWhenExhausted = closeWhenExhausted;
140 | this.flushImmediately = false;
141 | }
142 |
143 | /**
144 | * Create a new stream pumper.
145 | *
146 | * @param is input stream to read data from
147 | * @param os output stream to write data to.
148 | */
149 | public StreamPumper(final InputStream is, final OutputStream os) {
150 | this(is, os, false);
151 | }
152 |
153 | /**
154 | * Copies data from the input stream to the output stream. Terminates as
155 | * soon as the input stream is closed or an error occurs.
156 | */
157 | public void run() {
158 | log.trace("{} started.", this);
159 | synchronized (this) {
160 | // Just in case this object is reused in the future
161 | finished = false;
162 | }
163 |
164 | final byte[] buf = new byte[this.size];
165 |
166 | int length;
167 | try {
168 | while ((length = is.read(buf)) > 0) {
169 | os.write(buf, 0, length);
170 | if(flushImmediately) {
171 | os.flush();
172 | }
173 | }
174 | } catch (Exception e) {
175 | // nothing to do - happens quite often with watchdog
176 | } finally {
177 | log.trace("{} finished.", this);
178 | if (closeWhenExhausted) {
179 | try {
180 | os.close();
181 | } catch (IOException e) {
182 | log.error("Got exception while closing exhausted output stream", e);
183 | }
184 | }
185 | synchronized (this) {
186 | finished = true;
187 | notifyAll();
188 | }
189 | }
190 | }
191 |
192 | /**
193 | * Tells whether the end of the stream has been reached.
194 | *
195 | * @return true is the stream has been exhausted.
196 | */
197 | public synchronized boolean isFinished() {
198 | return finished;
199 | }
200 |
201 | /**
202 | * This method blocks until the stream pumper finishes.
203 | *
204 | * @see #isFinished()
205 | * @throws InterruptedException throws when the waiting is interrupted
206 | */
207 | public synchronized void waitFor() throws InterruptedException {
208 | while (!isFinished()) {
209 | wait();
210 | }
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/TeeOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Ketan Padegaonkar
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.zeroturnaround.exec.stream;
18 |
19 | import java.io.IOException;
20 | import java.io.OutputStream;
21 |
22 | /**
23 | * Splits an OutputStream into two. Named after the unix 'tee'
24 | * command. It allows a stream to be branched off so there
25 | * are now two streams.
26 | */
27 | public class TeeOutputStream extends OutputStream {
28 | private final OutputStream left;
29 | private final OutputStream right;
30 |
31 | public TeeOutputStream(OutputStream left, OutputStream right) {
32 | this.left = left;
33 | this.right = right;
34 | }
35 |
36 | /**
37 | * Write a byte array to both output streams.
38 | *
39 | * @param b the data.
40 | * @param off the start offset in the data.
41 | * @param len the number of bytes to write.
42 | * @throws IOException on error.
43 | */
44 | public void write(byte[] b, int off, int len) throws IOException {
45 | left.write(b, off, len);
46 | right.write(b, off, len);
47 | }
48 |
49 |
50 | /**
51 | * Write a byte to both output streams.
52 | *
53 | * @param b the byte to write.
54 | * @throws IOException on error.
55 | */
56 | public void write(int b) throws IOException {
57 | left.write(b);
58 | right.write(b);
59 | }
60 |
61 |
62 | /**
63 | * Write a byte array to both output streams.
64 | *
65 | * @param b an array of bytes.
66 | * @throws IOException on error.
67 | */
68 | public void write(byte[] b) throws IOException {
69 | left.write(b);
70 | right.write(b);
71 | }
72 |
73 | /**
74 | * Closes both output streams
75 | *
76 | * @throws IOException on error.
77 | */
78 | @Override
79 | public void close() throws IOException {
80 | try {
81 | left.close();
82 | } finally {
83 | right.close();
84 | }
85 | }
86 |
87 |
88 | /**
89 | * Flush both output streams.
90 | *
91 | * @throws IOException on error
92 | */
93 | @Override
94 | public void flush() throws IOException {
95 | left.flush();
96 | right.flush();
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/slf4j/Level.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.stream.slf4j;
2 |
3 | /**
4 | * Slf4j logging level.
5 | */
6 | public enum Level {
7 |
8 | TRACE,
9 | DEBUG,
10 | INFO,
11 | WARN,
12 | ERROR
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/slf4j/Slf4jDebugOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stream.slf4j;
19 |
20 | import org.slf4j.Logger;
21 |
22 | /**
23 | * Output stream that writes debug
level messages to a given {@link Logger}.
24 | *
25 | * @author Rein Raudjärv
26 | */
27 | public class Slf4jDebugOutputStream extends Slf4jOutputStream {
28 |
29 | public Slf4jDebugOutputStream(Logger logger) {
30 | super(logger);
31 | }
32 |
33 | @Override
34 | protected void processLine(String line) {
35 | log.debug(line);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/slf4j/Slf4jErrorOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stream.slf4j;
19 |
20 | import org.slf4j.Logger;
21 |
22 | /**
23 | * Output stream that writes error
level messages to a given {@link Logger}.
24 | *
25 | * @author Rein Raudjärv
26 | */
27 | public class Slf4jErrorOutputStream extends Slf4jOutputStream {
28 |
29 | public Slf4jErrorOutputStream(Logger logger) {
30 | super(logger);
31 | }
32 |
33 | @Override
34 | protected void processLine(String line) {
35 | log.error(line);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/slf4j/Slf4jInfoOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stream.slf4j;
19 |
20 | import org.slf4j.Logger;
21 |
22 | /**
23 | * Output stream that writes info
level messages to a given {@link Logger}.
24 | *
25 | * @author Rein Raudjärv
26 | */
27 | public class Slf4jInfoOutputStream extends Slf4jOutputStream {
28 |
29 | public Slf4jInfoOutputStream(Logger logger) {
30 | super(logger);
31 | }
32 |
33 | @Override
34 | protected void processLine(String line) {
35 | log.info(line);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/slf4j/Slf4jOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stream.slf4j;
19 |
20 | import org.slf4j.Logger;
21 | import org.zeroturnaround.exec.stream.LogOutputStream;
22 |
23 | /**
24 | * Output stream that writes to a given {@link Logger}.
25 | *
26 | * @author Rein Raudjärv
27 | */
28 | public abstract class Slf4jOutputStream extends LogOutputStream {
29 |
30 | protected final Logger log;
31 |
32 | public Slf4jOutputStream(Logger logger) {
33 | this.log = logger;
34 | }
35 |
36 | public Logger getLogger() {
37 | return log;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/slf4j/Slf4jStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stream.slf4j;
19 |
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 | import org.zeroturnaround.exec.stream.CallerLoggerUtil;
23 |
24 | /**
25 | * Creates output streams that write to {@link Logger}s.
26 | *
27 | * @author Rein Raudjärv
28 | */
29 | public class Slf4jStream {
30 |
31 | private final Logger log;
32 |
33 | private Slf4jStream(Logger log) {
34 | this.log = log;
35 | }
36 |
37 | /**
38 | * @param log logger which an output stream redirects to.
39 | * @return Slf4jStream with the given logger.
40 | */
41 | public static Slf4jStream of(Logger log) {
42 | return new Slf4jStream(log);
43 | }
44 |
45 | /**
46 | * @param klass class which is used to get the logger's name.
47 | * @return Slf4jStream with a logger named after the given class.
48 | */
49 | public static Slf4jStream of(Class> klass) {
50 | return of(LoggerFactory.getLogger(klass));
51 | }
52 |
53 | /**
54 | * Constructs a logger from a class name and an additional name,
55 | * appended to the end. So the final logger name will be:
56 | * klass.getName() + "." + name
57 | *
58 | * @param klass class which is used to get the logger's name.
59 | * @param name logger's name, appended to the class name.
60 | * @return Slf4jStream with a logger named after the given class.
61 | *
62 | * @since 1.8
63 | */
64 | public static Slf4jStream of(Class> klass, String name) {
65 | if (name == null) {
66 | return of(klass);
67 | } else {
68 | return of(LoggerFactory.getLogger(klass.getName() + "." + name));
69 | }
70 | }
71 |
72 | /**
73 | * @param name logger's name (full or short).
74 | * In case of short name (no dots) the given name is prefixed by caller's class name and a dot.
75 | * @return Slf4jStream with the given logger.
76 | */
77 | public static Slf4jStream of(String name) {
78 | return of(LoggerFactory.getLogger(CallerLoggerUtil.getName(name, 1)));
79 | }
80 |
81 | /**
82 | * @return Slf4jStream with the logger of caller of this method.
83 | */
84 | public static Slf4jStream ofCaller() {
85 | return of(LoggerFactory.getLogger(CallerLoggerUtil.getName(null, 1)));
86 | }
87 |
88 | /**
89 | * @param level the desired logging level
90 | * @return output stream that writes with a given level.
91 | */
92 | public Slf4jOutputStream as(Level level) {
93 | switch (level) {
94 | case TRACE: return asTrace();
95 | case DEBUG: return asDebug();
96 | case INFO: return asInfo();
97 | case WARN: return asWarn();
98 | case ERROR: return asError();
99 | }
100 | throw new IllegalArgumentException("Invalid level " + level);
101 | }
102 |
103 | /**
104 | * @return output stream that writes trace
level.
105 | */
106 | public Slf4jOutputStream asTrace() {
107 | return new Slf4jTraceOutputStream(log);
108 | }
109 |
110 | /**
111 | * @return output stream that writes debug
level.
112 | */
113 | public Slf4jOutputStream asDebug() {
114 | return new Slf4jDebugOutputStream(log);
115 | }
116 |
117 | /**
118 | * @return output stream that writes info
level.
119 | */
120 | public Slf4jOutputStream asInfo() {
121 | return new Slf4jInfoOutputStream(log);
122 | }
123 |
124 | /**
125 | * @return output stream that writes warn
level.
126 | */
127 | public Slf4jOutputStream asWarn() {
128 | return new Slf4jWarnOutputStream(log);
129 | }
130 |
131 | /**
132 | * @return output stream that writes error
level.
133 | */
134 | public Slf4jOutputStream asError() {
135 | return new Slf4jErrorOutputStream(log);
136 | }
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/slf4j/Slf4jTraceOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stream.slf4j;
19 |
20 | import org.slf4j.Logger;
21 |
22 | /**
23 | * Output stream that writes trace
level messages to a given {@link Logger}.
24 | *
25 | * @author Rein Raudjärv
26 | */
27 | public class Slf4jTraceOutputStream extends Slf4jOutputStream {
28 |
29 | public Slf4jTraceOutputStream(Logger logger) {
30 | super(logger);
31 | }
32 |
33 | @Override
34 | protected void processLine(String line) {
35 | log.trace(line);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/zeroturnaround/exec/stream/slf4j/Slf4jWarnOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.stream.slf4j;
19 |
20 | import org.slf4j.Logger;
21 |
22 | /**
23 | * Output stream that writes warn
level messages to a given {@link Logger}.
24 | *
25 | * @author Rein Raudjärv
26 | */
27 | public class Slf4jWarnOutputStream extends Slf4jOutputStream {
28 |
29 | public Slf4jWarnOutputStream(Logger logger) {
30 | super(logger);
31 | }
32 |
33 | @Override
34 | protected void processLine(String line) {
35 | log.warn(line);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/ProcessOutputTest.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec;
2 |
3 | import java.util.Arrays;
4 |
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 |
8 | public class ProcessOutputTest {
9 |
10 | @Test(expected = NullPointerException.class)
11 | public void testNull() {
12 | ProcessOutput.getLinesFrom(null);
13 | }
14 |
15 | @Test
16 | public void testSimple() {
17 | Assert.assertEquals(Arrays.asList("foo"), ProcessOutput.getLinesFrom("foo"));
18 | }
19 |
20 | @Test
21 | public void testNewLine() {
22 | Assert.assertEquals(Arrays.asList("foo", "bar"), ProcessOutput.getLinesFrom("foo\nbar"));
23 | }
24 |
25 | @Test
26 | public void testNewLineWithMultipleLines() {
27 | Assert.assertEquals(Arrays.asList("foo1", "bar1", "foo2", "bar2"), ProcessOutput.getLinesFrom("foo1\nbar1\nfoo2\nbar2"));
28 | }
29 |
30 | @Test
31 | public void testCarriageReturn() {
32 | Assert.assertEquals(Arrays.asList("foo", "bar"), ProcessOutput.getLinesFrom("foo\rbar"));
33 | }
34 |
35 | @Test
36 | public void testCarriageReturnWithMultipleLines() {
37 | Assert.assertEquals(Arrays.asList("foo1", "bar1", "foo2", "bar2"), ProcessOutput.getLinesFrom("foo1\rbar1\rfoo2\rbar2"));
38 | }
39 |
40 | @Test
41 | public void testCarriageReturnAndNewLine() {
42 | Assert.assertEquals(Arrays.asList("foo", "bar"), ProcessOutput.getLinesFrom("foo\r\nbar"));
43 | }
44 |
45 | @Test
46 | public void testCarriageReturnAndNewLineWithMultipleLines() {
47 | Assert.assertEquals(Arrays.asList("foo1", "bar1", "foo2", "bar2"), ProcessOutput.getLinesFrom("foo1\r\nbar1\r\nfoo2\r\nbar2"));
48 | }
49 |
50 | @Test
51 | public void testTwoNewLines() {
52 | Assert.assertEquals(Arrays.asList("foo", "bar"), ProcessOutput.getLinesFrom("foo\n\nbar"));
53 | }
54 |
55 | @Test
56 | public void testNewLineAtTheEnd() {
57 | Assert.assertEquals(Arrays.asList("foo"), ProcessOutput.getLinesFrom("foo\n"));
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/ReadmeExamples.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec;
2 |
3 | import java.io.OutputStream;
4 | import java.util.Map;
5 | import java.util.concurrent.Future;
6 | import java.util.concurrent.TimeUnit;
7 | import java.util.concurrent.TimeoutException;
8 |
9 | import org.slf4j.LoggerFactory;
10 | import org.zeroturnaround.exec.stream.LogOutputStream;
11 | import org.zeroturnaround.exec.stream.slf4j.Slf4jStream;
12 |
13 | /**
14 | * Examples of the readme.
15 | */
16 | class ReadmeExamples {
17 |
18 | void justExecute() throws Exception {
19 | new ProcessExecutor().command("java", "-version").execute();
20 | }
21 |
22 | int getExitCode() throws Exception {
23 | int exit = new ProcessExecutor().command("java", "-version")
24 | .execute().getExitValue();
25 | return exit;
26 | }
27 |
28 | String getOutput() throws Exception {
29 | String output = new ProcessExecutor().command("java", "-version")
30 | .readOutput(true).execute()
31 | .outputUTF8();
32 | return output;
33 | }
34 |
35 | void pumpOutputToLogger() throws Exception {
36 | new ProcessExecutor().command("java", "-version")
37 | .redirectOutput(Slf4jStream.of(LoggerFactory.getLogger(getClass().getName() + ".MyProcess")).asInfo()).execute();
38 | }
39 |
40 | void pumpOutputToLoggerShorter() throws Exception {
41 | new ProcessExecutor().command("java", "-version")
42 | .redirectOutput(Slf4jStream.of("MyProcess").asInfo()).execute();
43 | }
44 |
45 | void pumpOutputToLoggerOfCaller() throws Exception {
46 | new ProcessExecutor().command("java", "-version")
47 | .redirectOutput(Slf4jStream.ofCaller().asInfo()).execute();
48 | }
49 |
50 | String pumpOutputToLoggerAndGetOutput() throws Exception {
51 | String output = new ProcessExecutor().command("java", "-version")
52 | .redirectOutput(Slf4jStream.of(getClass()).asInfo())
53 | .readOutput(true).execute().outputUTF8();
54 | return output;
55 | }
56 |
57 | String pumpErrorToLoggerAndGetOutput() throws Exception {
58 | String output = new ProcessExecutor().command("java", "-version")
59 | .redirectError(Slf4jStream.of(getClass()).asInfo())
60 | .readOutput(true).execute()
61 | .outputUTF8();
62 | return output;
63 | }
64 |
65 | void executeWithTimeout() throws Exception {
66 | try {
67 | new ProcessExecutor().command("java", "-version")
68 | .timeout(60, TimeUnit.SECONDS).execute();
69 | }
70 | catch (TimeoutException e) {
71 | // process is automatically destroyed
72 | }
73 | }
74 |
75 | void pumpOutputToStream(OutputStream out) throws Exception {
76 | new ProcessExecutor().command("java", "-version")
77 | .redirectOutput(out).execute();
78 | }
79 |
80 | void pumpOutputToLogStream(OutputStream out) throws Exception {
81 | new ProcessExecutor().command("java", "-version")
82 | .redirectOutput(new LogOutputStream() {
83 | @Override
84 | protected void processLine(String line) {
85 | // ...
86 | }
87 | })
88 | .execute();
89 | }
90 |
91 | void destroyProcessOnJvmExit() throws Exception {
92 | new ProcessExecutor().command("java", "-version").destroyOnExit().execute();
93 | }
94 |
95 | void executeWithEnvironmentVariable() throws Exception {
96 | new ProcessExecutor().command("java", "-version")
97 | .environment("foo", "bar")
98 | .execute();
99 | }
100 |
101 | void executeWithEnvironment(Map env) throws Exception {
102 | new ProcessExecutor().command("java", "-version")
103 | .environment(env)
104 | .execute();
105 | }
106 |
107 | void checkExitCode() throws Exception {
108 | try {
109 | new ProcessExecutor().command("java", "-version")
110 | .exitValues(3).execute();
111 | }
112 | catch (InvalidExitValueException e) {
113 | System.out.println("Process exited with " + e.getExitValue());
114 | }
115 | }
116 |
117 | void checkExitCodeAndGetOutput() throws Exception {
118 | String output;
119 | boolean success = false;
120 | try {
121 | output = new ProcessExecutor().command("java", "-version")
122 | .readOutput(true).exitValues(3)
123 | .execute().outputUTF8();
124 | success = true;
125 | }
126 | catch (InvalidExitValueException e) {
127 | System.out.println("Process exited with " + e.getExitValue());
128 | output = e.getResult().outputUTF8();
129 | }
130 | }
131 |
132 | void startInBackground() throws Exception {
133 | Future future = new ProcessExecutor()
134 | .command("java", "-version")
135 | .start().getFuture();
136 | //do some stuff
137 | future.get(60, TimeUnit.SECONDS);
138 | }
139 |
140 | String startInBackgroundAndGetOutput() throws Exception {
141 | Future future = new ProcessExecutor()
142 | .command("java", "-version")
143 | .readOutput(true)
144 | .start().getFuture();
145 | //do some stuff
146 | String output = future.get(60, TimeUnit.SECONDS).outputUTF8();
147 | return output;
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/stream/TeeOutputStreamTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Ketan Padegaonkar
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.zeroturnaround.exec.stream;
18 |
19 | import org.junit.Assert;
20 | import org.junit.Test;
21 | import org.zeroturnaround.exec.test.RememberCloseOutputStream;
22 |
23 | import java.io.ByteArrayOutputStream;
24 | import java.io.IOException;
25 | import java.io.OutputStream;
26 |
27 | public class TeeOutputStreamTest {
28 |
29 | public static class ExceptionOnCloseByteArrayOutputStream extends RememberCloseOutputStream {
30 |
31 | public ExceptionOnCloseByteArrayOutputStream(OutputStream out) {
32 | super(out);
33 | }
34 |
35 | @Override
36 | public void close() throws IOException {
37 | super.close();
38 | throw new IOException();
39 | }
40 | }
41 |
42 | @Test
43 | public void shouldCopyContentsToBothStreams() throws IOException {
44 | ByteArrayOutputStream left = new ByteArrayOutputStream();
45 | ByteArrayOutputStream right = new ByteArrayOutputStream();
46 | TeeOutputStream teeOutputStream = new TeeOutputStream(left, right);
47 |
48 | teeOutputStream.write(10);
49 | teeOutputStream.write(new byte[]{1, 2, 3});
50 | teeOutputStream.write(new byte[]{10, 11, 12, 13, 14, 15, 15, 16}, 2, 3);
51 |
52 | Assert.assertArrayEquals(new byte[]{10, 1, 2, 3, 12, 13, 14}, left.toByteArray());
53 | Assert.assertArrayEquals(new byte[]{10, 1, 2, 3, 12, 13, 14}, right.toByteArray());
54 | }
55 |
56 | @Test
57 | public void shouldCloseBothStreamsWhenClosingTee() throws IOException {
58 | RememberCloseOutputStream left = new RememberCloseOutputStream(NullOutputStream.NULL_OUTPUT_STREAM);
59 | RememberCloseOutputStream right = new RememberCloseOutputStream(NullOutputStream.NULL_OUTPUT_STREAM);
60 | TeeOutputStream teeOutputStream = new TeeOutputStream(left, right);
61 |
62 | teeOutputStream.close();
63 |
64 | Assert.assertTrue(left.isClosed());
65 | Assert.assertTrue(right.isClosed());
66 | }
67 |
68 | @Test
69 | public void shouldCloseSecondStreamWhenClosingFirstFails() {
70 | ExceptionOnCloseByteArrayOutputStream left = new ExceptionOnCloseByteArrayOutputStream(NullOutputStream.NULL_OUTPUT_STREAM);
71 | RememberCloseOutputStream right = new RememberCloseOutputStream(NullOutputStream.NULL_OUTPUT_STREAM);
72 | TeeOutputStream teeOutputStream = new TeeOutputStream(left, right);
73 | try {
74 | teeOutputStream.close();
75 | Assert.fail("Was expecting an exception!");
76 | } catch (IOException expected) {
77 |
78 | }
79 |
80 | Assert.assertTrue(left.isClosed());
81 | Assert.assertTrue(right.isClosed());
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ArgumentsAsList.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.util.Arrays;
21 |
22 | public class ArgumentsAsList {
23 |
24 | public static void main(String[] args) {
25 | System.out.print(Arrays.asList(args));
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/BigOutput.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | public class BigOutput {
21 |
22 | public static final int LENGTH = 100000;
23 |
24 | public static void main(String[] args) {
25 | for (int i = 0; i < LENGTH; i++) {
26 | System.out.print("+");
27 | System.err.print("-");
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/CallerLoggerUtilTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import org.junit.Assert;
21 | import org.junit.Test;
22 | import org.zeroturnaround.exec.stream.CallerLoggerUtil;
23 |
24 |
25 | public class CallerLoggerUtilTest {
26 |
27 | @Test
28 | public void testFullName() throws Exception {
29 | String fullName = "my.full.Logger";
30 | Assert.assertEquals(fullName, CallerLoggerUtil.getName(fullName));
31 | }
32 |
33 | @Test
34 | public void testShortName() throws Exception {
35 | String shortName = "MyLogger";
36 | String fullName = getClass().getName() + "." + shortName;
37 | Assert.assertEquals(fullName, CallerLoggerUtil.getName(shortName));
38 | }
39 |
40 | @Test
41 | public void testMyClassName() throws Exception {
42 | String fullName = getClass().getName();
43 | Assert.assertEquals(fullName, CallerLoggerUtil.getName(null));
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/EmptyArgTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import org.junit.Assert;
21 | import org.junit.Test;
22 | import org.zeroturnaround.exec.ProcessExecutor;
23 |
24 | import java.util.ArrayList;
25 | import java.util.Arrays;
26 | import java.util.List;
27 |
28 | /**
29 | * Tests passing empty arguments.
30 | *
31 | * @see ProcessExecutor
32 | * @see ArgumentsAsList
33 | */
34 | public class EmptyArgTest {
35 |
36 | @Test
37 | public void testReadOutputAndError() throws Exception {
38 | String output = argumentsAsList("arg1", "", "arg3", "").readOutput(true).execute().outputUTF8();
39 | Assert.assertEquals("[arg1, , arg3, ]", output);
40 | }
41 |
42 | private ProcessExecutor argumentsAsList(String... args) {
43 | List command = new ArrayList();
44 | command.addAll(Arrays.asList("java", "-cp", "target/test-classes", ArgumentsAsList.class.getName()));
45 | command.addAll(Arrays.asList(args));
46 | return new ProcessExecutor(command);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ExitLikeABoss.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | public class ExitLikeABoss {
21 | public static void main(String[] args) {
22 | int exitCode = 0;
23 | if (args.length>0) {
24 | try {
25 | exitCode = Integer.parseInt(args[0]);
26 | }
27 | catch (NumberFormatException e) {
28 | System.out.println("Please provide valid exit code as parameter");
29 | }
30 | }
31 | System.exit(exitCode);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/HelloWorld.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | public class HelloWorld {
21 |
22 | public static void main(String[] args) {
23 | System.out.print("Hello ");
24 | System.err.print("world!");
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/InputRedirectTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.ByteArrayInputStream;
21 |
22 | import org.apache.commons.lang3.SystemUtils;
23 | import org.junit.Assume;
24 | import org.junit.Test;
25 | import org.slf4j.Logger;
26 | import org.slf4j.LoggerFactory;
27 | import org.zeroturnaround.exec.ProcessExecutor;
28 |
29 | /**
30 | * Reported in https://github.com/zeroturnaround/zt-exec/issues/30
31 | */
32 | public class InputRedirectTest {
33 |
34 | private static final Logger log = LoggerFactory.getLogger(InputRedirectTest.class);
35 |
36 | @Test
37 | public void testRedirectInput() throws Exception {
38 | String binTrue;
39 | if (SystemUtils.IS_OS_LINUX) {
40 | binTrue = "/bin/true";
41 | }
42 | else if (SystemUtils.IS_OS_MAC_OSX) {
43 | binTrue = "/usr/bin/true";
44 | }
45 | else {
46 | Assume.assumeTrue("Unsupported OS " + SystemUtils.OS_NAME, false);
47 | return; // Skip this test
48 | }
49 |
50 | // We need to put something in the buffer
51 | ByteArrayInputStream bais = new ByteArrayInputStream("foo".getBytes());
52 | ProcessExecutor exec = new ProcessExecutor().command(binTrue);
53 | // Test that we don't get IOException: Stream closed
54 | int exit = exec.redirectInput(bais).readOutput(true).execute().getExitValue();
55 | log.debug("Exit: {}", exit);
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/InputStreamPumperTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.ByteArrayInputStream;
21 | import java.io.ByteArrayOutputStream;
22 |
23 | import org.junit.Assert;
24 | import org.junit.Test;
25 | import org.zeroturnaround.exec.ProcessExecutor;
26 | import org.zeroturnaround.exec.stream.PumpStreamHandler;
27 |
28 | /**
29 | * Tests that test redirected input for the process to be run.
30 | */
31 | public class InputStreamPumperTest {
32 |
33 | @Test
34 | public void testPumpFromInputToOutput() throws Exception {
35 | String str = "Tere Minu Uus vihik";
36 | ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
37 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
38 | PumpStreamHandler handler = new PumpStreamHandler(baos, System.err, bais);
39 |
40 | ProcessExecutor exec = new ProcessExecutor("java", "-cp", "target/test-classes",
41 | PrintInputToOutput.class.getName()).readOutput(true);
42 | exec.streams(handler);
43 |
44 | String result = exec.execute().outputUTF8();
45 | Assert.assertEquals(str, result);
46 | }
47 |
48 | @Test
49 | public void testPumpFromInputToOutputWithInput() throws Exception {
50 | String str = "Tere Minu Uus vihik";
51 | ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
52 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
53 |
54 | ProcessExecutor exec = new ProcessExecutor("java", "-cp", "target/test-classes",
55 | PrintInputToOutput.class.getName()).readOutput(true).redirectInput(bais);
56 |
57 | String result = exec.execute().outputUTF8();
58 | Assert.assertEquals(str, result);
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/LogOutputStreamTest.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.test;
2 |
3 | import java.io.IOException;
4 | import java.io.UnsupportedEncodingException;
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | import org.junit.Assert;
10 | import org.junit.Test;
11 | import org.zeroturnaround.exec.stream.LineConsumer;
12 | import org.zeroturnaround.exec.stream.LogOutputStream;
13 |
14 | public class LogOutputStreamTest {
15 |
16 | private void testLogOutputStream(String multiLineString, String... expectedLines) throws UnsupportedEncodingException, IOException {
17 | final List processedLines = new ArrayList();
18 | LogOutputStream logOutputStream = new LogOutputStream() {
19 |
20 | @Override
21 | protected void processLine(String line) {
22 | processedLines.add(line);
23 | }
24 | };
25 | try {
26 | logOutputStream.write(multiLineString.getBytes("UTF-8"));
27 | } finally {
28 | logOutputStream.close();
29 | }
30 | Assert.assertEquals(Arrays.asList(expectedLines), processedLines);
31 | }
32 |
33 | @Test
34 | public void testSimple() throws UnsupportedEncodingException, IOException {
35 | testLogOutputStream("foo", "foo");
36 | }
37 |
38 | @Test
39 | public void testNewLine() throws UnsupportedEncodingException, IOException {
40 | testLogOutputStream("foo\nbar", "foo", "bar");
41 | }
42 |
43 | @Test
44 | public void testNewLineWithMultipleLines() throws UnsupportedEncodingException, IOException {
45 | testLogOutputStream("foo1\nbar1\nfoo2\nbar2", "foo1", "bar1", "foo2", "bar2");
46 | }
47 |
48 | @Test
49 | public void testCarriageReturn() throws UnsupportedEncodingException, IOException {
50 | testLogOutputStream("foo\rbar", "foo", "bar");
51 | }
52 |
53 | @Test
54 | public void testCarriageReturnWithMultipleLines() throws UnsupportedEncodingException, IOException {
55 | testLogOutputStream("foo1\rbar1\rfoo2\rbar2", "foo1", "bar1", "foo2", "bar2");
56 | }
57 |
58 | @Test
59 | public void testCarriageReturnAndNewLine() throws UnsupportedEncodingException, IOException {
60 | testLogOutputStream("foo\r\nbar", "foo", "bar");
61 | }
62 |
63 | @Test
64 | public void testCarriageReturnAndNewLineWithMultipleLines() throws UnsupportedEncodingException, IOException {
65 | testLogOutputStream("foo1\r\nbar1\r\nfoo2\r\nbar2", "foo1", "bar1", "foo2", "bar2");
66 | }
67 |
68 | @Test
69 | public void testTwoNewLines() throws UnsupportedEncodingException, IOException {
70 | testLogOutputStream("foo\n\nbar", "foo", "bar");
71 | }
72 |
73 | @Test
74 | public void testNewLineAtTheEnd() throws UnsupportedEncodingException, IOException {
75 | testLogOutputStream("foo\n", "foo");
76 | }
77 |
78 | @Test
79 | public void lambda() throws IOException {
80 | final List lines = new ArrayList();
81 | LogOutputStream out = LogOutputStream.create(new LineConsumer() {
82 | @Override
83 | public void accept(String line) {
84 | lines.add(line);
85 | }
86 | });
87 | out.write("foo\nbar\n".getBytes());
88 | Assert.assertEquals(Arrays.asList("foo", "bar"), lines);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/Loop.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.test;
2 |
3 | import java.io.PrintStream;
4 |
5 | class Loop {
6 |
7 | private static final long INTERVAL = 1000;
8 | private static final long COUNT = 10;
9 |
10 | public static void main(String[] args) throws Exception {
11 | PrintStream out = System.out;
12 | out.println("Started");
13 | for (int i = 0; i < COUNT; i++) {
14 | out.println(i);
15 | Thread.sleep(INTERVAL);
16 | }
17 | out.println("Finished");
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/MockProcessDestroyer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import org.zeroturnaround.exec.listener.ProcessDestroyer;
21 |
22 | public class MockProcessDestroyer implements ProcessDestroyer {
23 |
24 | volatile Process added;
25 | volatile Process removed;
26 |
27 | public boolean add(Process process) {
28 | added = process;
29 | return true;
30 | }
31 |
32 | public boolean remove(Process process) {
33 | removed = process;
34 | return true;
35 | }
36 |
37 | public int size() {
38 | return 0;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/PrintArguments.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.test;
2 |
3 | public class PrintArguments {
4 |
5 | public static void main(String[] args) {
6 | for (String arg : args) {
7 | System.out.println(arg);
8 | }
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/PrintInputToOutput.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.test;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStreamReader;
5 |
6 | public class PrintInputToOutput {
7 | public static void main(String[] args) throws Exception {
8 | InputStreamReader isr = new InputStreamReader(System.in);
9 | BufferedReader br = new BufferedReader(isr);
10 |
11 | String line = null;
12 | int count = 0;
13 | while ((line = br.readLine()) != null) {
14 | System.out.print(line);
15 | count++;
16 | if (count == 3)
17 | break;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorArgsWithExtraSpaceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import org.junit.Assert;
21 | import org.junit.Test;
22 | import org.zeroturnaround.exec.ProcessExecutor;
23 |
24 |
25 | /**
26 | * Tests argument splitting.
27 | *
28 | * @see ProcessExecutor
29 | * @see ArgumentsAsList
30 | */
31 | public class ProcessExecutorArgsWithExtraSpaceTest {
32 |
33 | @Test
34 | public void testReadOutputAndError() throws Exception {
35 | String output = argumentsAsList("arg1 arg2 arg3").readOutput(true).execute().outputUTF8();
36 | Assert.assertEquals("[arg1, arg2, arg3]", output);
37 | }
38 |
39 | private ProcessExecutor argumentsAsList(String args) {
40 | return new ProcessExecutor().commandSplit("java -cp target/test-classes " + ArgumentsAsList.class.getName() + " " + args);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorBigOutputTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.ByteArrayOutputStream;
21 | import java.util.concurrent.TimeUnit;
22 |
23 | import org.junit.Assert;
24 | import org.junit.Test;
25 | import org.zeroturnaround.exec.ProcessExecutor;
26 |
27 |
28 | /**
29 | * Tests reading large output that doesn't fit into a buffer between this process and sub process.
30 | *
31 | * @author Rein Raudjärv
32 | *
33 | * @see ProcessExecutor
34 | * @see BigOutput
35 | */
36 | public class ProcessExecutorBigOutputTest {
37 |
38 | @Test
39 | public void testDevNull() throws Exception {
40 | bigOutput().execute();
41 | }
42 |
43 | @Test
44 | public void testDevNullSeparate() throws Exception {
45 | bigOutput().redirectErrorStream(false).execute();
46 | }
47 |
48 | @Test
49 | public void testReadOutputAndError() throws Exception {
50 | String output = bigOutput().readOutput(true).execute().outputUTF8();
51 | Assert.assertEquals(repeat("+-"), output);
52 | }
53 |
54 | @Test
55 | public void testReadOutputOnly() throws Exception {
56 | String output = bigOutput().readOutput(true).redirectErrorStream(false).execute().outputUTF8();
57 | Assert.assertEquals(repeat("+"), output);
58 | }
59 |
60 | @Test
61 | public void testRedirectOutputOnly() throws Exception {
62 | ByteArrayOutputStream out = new ByteArrayOutputStream();
63 | bigOutput().redirectOutput(out).redirectErrorStream(false).execute();
64 | Assert.assertEquals(repeat("+"), new String(out.toByteArray()));
65 | }
66 |
67 | @Test
68 | public void testRedirectErrorOnly() throws Exception {
69 | ByteArrayOutputStream err = new ByteArrayOutputStream();
70 | bigOutput().redirectError(err).redirectErrorStream(false).execute();
71 | Assert.assertEquals(repeat("-"), new String(err.toByteArray()));
72 | }
73 |
74 | private ProcessExecutor bigOutput() {
75 | // Use timeout in case we get stuck
76 | return new ProcessExecutor("java", "-cp", "target/test-classes", BigOutput.class.getName()).timeout(10, TimeUnit.SECONDS);
77 | }
78 |
79 | private static String repeat(String s) {
80 | StringBuffer sb = new StringBuffer(BigOutput.LENGTH * 2);
81 | for (int i = 0; i < BigOutput.LENGTH; i++)
82 | sb.append(s);
83 | return sb.toString();
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorCommandLineTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.ByteArrayInputStream;
21 | import java.io.IOException;
22 | import java.util.ArrayList;
23 | import java.util.Arrays;
24 | import java.util.List;
25 | import java.util.concurrent.TimeoutException;
26 |
27 | import org.apache.commons.io.IOUtils;
28 | import org.junit.Assert;
29 | import org.junit.Test;
30 | import org.zeroturnaround.exec.ProcessExecutor;
31 |
32 |
33 | /**
34 | * Tests passing command line arguments to a Java process.
35 | */
36 | public class ProcessExecutorCommandLineTest {
37 |
38 | @Test
39 | public void testOneArg() throws Exception {
40 | testArguments("foo");
41 | }
42 |
43 | @Test
44 | public void testTwoArgs() throws Exception {
45 | testArguments("foo", "bar");
46 | }
47 |
48 | @Test
49 | public void testSpaces() throws Exception {
50 | testArguments("foo foo", "bar bar");
51 | }
52 |
53 | @Test
54 | public void testQuotes() throws Exception {
55 | String[] args = new String[]{"\"a\"", "b \"c\" d", "f \"e\"", "\"g\" h"};
56 | List expected = Arrays.asList("\"a\"", "b \"c\" d", "f \"e\"", "\"g\" h");
57 | if (System.getProperty("os.name").startsWith("Windows"))
58 | expected = Arrays.asList("a", "b c d", "f e", "g h");
59 | testArguments(expected, args);
60 | }
61 |
62 | @Test
63 | public void testSlashes() throws Exception {
64 | testArguments("/o\\", "\\/.*");
65 | }
66 |
67 | private void testArguments(String... args) throws IOException, InterruptedException, TimeoutException {
68 | byte[] bytes = printArguments(args).execute().output();
69 | List expected = Arrays.asList(args);
70 | List actual = IOUtils.readLines(new ByteArrayInputStream(bytes));
71 | Assert.assertEquals(expected, actual);
72 | }
73 |
74 | private void testArguments(List expected, String... args) throws IOException, InterruptedException, TimeoutException {
75 | byte[] bytes = printArguments(args).execute().output();
76 | List actual = IOUtils.readLines(new ByteArrayInputStream(bytes));
77 | Assert.assertEquals(expected, actual);
78 | }
79 |
80 | private ProcessExecutor printArguments(String... args) {
81 | List command = new ArrayList();
82 | command.addAll(Arrays.asList("java", "-cp", "target/test-classes", PrintArguments.class.getName()));
83 | command.addAll(Arrays.asList(args));
84 | return new ProcessExecutor(command).readOutput(true);
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorExitValueTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 | import java.util.concurrent.TimeUnit;
23 |
24 | import org.junit.Test;
25 | import org.zeroturnaround.exec.InvalidExitValueException;
26 | import org.zeroturnaround.exec.ProcessExecutor;
27 |
28 |
29 | public class ProcessExecutorExitValueTest {
30 |
31 | @Test(expected=InvalidExitValueException.class)
32 | public void testJavaVersionExitValueCheck() throws Exception {
33 | new ProcessExecutor().command("java", "-version").exitValues(3).execute();
34 | }
35 |
36 | @Test(expected=InvalidExitValueException.class)
37 | public void testJavaVersionExitValueCheckTimeout() throws Exception {
38 | new ProcessExecutor().command("java", "-version").exitValues(3).timeout(60, TimeUnit.SECONDS).execute();
39 | }
40 |
41 | public void testNonZeroExitValueByDefault() throws Exception {
42 | new ProcessExecutor(exitLikeABoss(17)).execute();
43 | }
44 |
45 | @Test
46 | public void testCustomExitValueValid() throws Exception {
47 | new ProcessExecutor(exitLikeABoss(17)).exitValues(17).execute();
48 | }
49 |
50 | @Test(expected=InvalidExitValueException.class)
51 | public void testCustomExitValueInvalid() throws Exception {
52 | new ProcessExecutor(exitLikeABoss(17)).exitValues(15).execute();
53 | }
54 |
55 | private static List exitLikeABoss(int exitValue) {
56 | List result = new ArrayList();
57 | result.add("java");
58 | result.add("-cp");
59 | result.add("target/test-classes");
60 | result.add(ExitLikeABoss.class.getName());
61 | result.add(String.valueOf(exitValue));
62 | return result;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorHelloWorldTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.ByteArrayOutputStream;
21 |
22 | import org.junit.Assert;
23 | import org.junit.Test;
24 | import org.zeroturnaround.exec.ProcessExecutor;
25 |
26 |
27 | /**
28 | * Tests redirecting stream.
29 | *
30 | * @author Rein Raudjärv
31 | *
32 | * @see ProcessExecutor
33 | * @see HelloWorld
34 | */
35 | public class ProcessExecutorHelloWorldTest {
36 |
37 | @Test
38 | public void testReadOutputAndError() throws Exception {
39 | String output = helloWorld().readOutput(true).execute().outputUTF8();
40 | Assert.assertEquals("Hello world!", output);
41 | }
42 |
43 | @Test
44 | public void testReadOutputOnly() throws Exception {
45 | String output = helloWorld().readOutput(true).redirectErrorStream(false).execute().outputUTF8();
46 | Assert.assertEquals("Hello ", output);
47 | }
48 |
49 | @Test
50 | public void testRedirectOutputAndError() throws Exception {
51 | ByteArrayOutputStream out = new ByteArrayOutputStream();
52 | helloWorld().redirectOutput(out).execute();
53 | Assert.assertEquals("Hello world!", new String(out.toByteArray()));
54 | }
55 |
56 | @Test
57 | public void testRedirectOutputAndErrorMerged() throws Exception {
58 | ByteArrayOutputStream out = new ByteArrayOutputStream();
59 | ByteArrayOutputStream err = new ByteArrayOutputStream();
60 | helloWorld().redirectOutput(out).redirectError(err).execute();
61 | Assert.assertEquals("Hello ", new String(out.toByteArray()));
62 | Assert.assertEquals("world!", new String(err.toByteArray()));
63 | }
64 |
65 | @Test
66 | public void testRedirectOutputAndErrorAndReadOutput() throws Exception {
67 | ByteArrayOutputStream out = new ByteArrayOutputStream();
68 | String output = helloWorld().redirectOutput(out).readOutput(true).execute().outputUTF8();
69 | Assert.assertEquals("Hello world!", output);
70 | Assert.assertEquals("Hello world!", new String(out.toByteArray()));
71 | }
72 |
73 | @Test
74 | public void testRedirectOutputOnly() throws Exception {
75 | ByteArrayOutputStream out = new ByteArrayOutputStream();
76 | helloWorld().redirectOutput(out).redirectErrorStream(false).execute();
77 | Assert.assertEquals("Hello ", new String(out.toByteArray()));
78 | }
79 |
80 | @Test
81 | public void testRedirectOutputOnlyAndReadOutput() throws Exception {
82 | ByteArrayOutputStream out = new ByteArrayOutputStream();
83 | String output = helloWorld().redirectOutput(out).redirectErrorStream(false).readOutput(true).execute().outputUTF8();
84 | Assert.assertEquals("Hello ", output);
85 | Assert.assertEquals("Hello ", new String(out.toByteArray()));
86 | }
87 |
88 | @Test
89 | public void testRedirectErrorOnly() throws Exception {
90 | ByteArrayOutputStream err = new ByteArrayOutputStream();
91 | helloWorld().redirectError(err).redirectErrorStream(false).execute();
92 | Assert.assertEquals("world!", new String(err.toByteArray()));
93 | }
94 |
95 | @Test
96 | public void testRedirectErrorOnlyAndReadOutput() throws Exception {
97 | ByteArrayOutputStream err = new ByteArrayOutputStream();
98 | String output = helloWorld().redirectError(err).redirectErrorStream(false).readOutput(true).execute().outputUTF8();
99 | Assert.assertEquals("Hello ", output);
100 | Assert.assertEquals("world!", new String(err.toByteArray()));
101 | }
102 |
103 | @Test
104 | public void testRedirectOutputAndErrorSeparate() throws Exception {
105 | ByteArrayOutputStream out = new ByteArrayOutputStream();
106 | ByteArrayOutputStream err = new ByteArrayOutputStream();
107 | helloWorld().redirectOutput(out).redirectError(err).redirectErrorStream(false).execute();
108 | Assert.assertEquals("Hello ", new String(out.toByteArray()));
109 | Assert.assertEquals("world!", new String(err.toByteArray()));
110 | }
111 |
112 | @Test
113 | public void testRedirectOutputAndErrorSeparateAndReadOutput() throws Exception {
114 | ByteArrayOutputStream out = new ByteArrayOutputStream();
115 | ByteArrayOutputStream err = new ByteArrayOutputStream();
116 | String output = helloWorld().redirectOutput(out).redirectError(err).redirectErrorStream(false).readOutput(true).execute().outputUTF8();
117 | Assert.assertEquals("Hello ", output);
118 | Assert.assertEquals("Hello ", new String(out.toByteArray()));
119 | Assert.assertEquals("world!", new String(err.toByteArray()));
120 | }
121 |
122 | private ProcessExecutor helloWorld() {
123 | return new ProcessExecutor("java", "-cp", "target/test-classes", HelloWorld.class.getName());
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorInputStreamTest.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.test;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.PipedInputStream;
6 | import java.io.PipedOutputStream;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | import org.junit.Assert;
10 | import org.junit.Test;
11 | import org.zeroturnaround.exec.ProcessExecutor;
12 | import org.zeroturnaround.exec.StartedProcess;
13 |
14 | /**
15 | *
16 | */
17 | public class ProcessExecutorInputStreamTest {
18 |
19 | @Test
20 | public void testWithInputAndRedirectOutput() throws Exception {
21 | String str = "Tere Minu Uus vihik";
22 | ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
23 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
24 |
25 | ProcessExecutor exec = new ProcessExecutor("java", "-cp", "target/test-classes", PrintInputToOutput.class.getName());
26 | exec.redirectInput(bais).redirectOutput(baos);
27 |
28 | exec.execute();
29 | Assert.assertEquals(str, baos.toString());
30 | }
31 |
32 | @Test
33 | public void testRedirectPipedInputStream() throws Exception {
34 | // Setup InputStream that will block on a read()
35 | PipedOutputStream pos = new PipedOutputStream();
36 | PipedInputStream pis = new PipedInputStream(pos);
37 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
38 |
39 | ProcessExecutor exec = new ProcessExecutor("java", "-cp", "target/test-classes", PrintArguments.class.getName());
40 | exec.redirectInput(pis);
41 | StartedProcess startedProcess = exec.start();
42 | // Assert that we don't get a TimeoutException
43 | startedProcess.getFuture().get(5, TimeUnit.SECONDS);
44 | }
45 |
46 | @Test
47 | public void testDataIsFlushedToProcessWithANonEndingInputStream() throws Exception {
48 | String str = "Tere Minu Uus vihik " + System.nanoTime();
49 |
50 | // Setup InputStream that will block on a read()
51 | PipedOutputStream pos = new PipedOutputStream();
52 | PipedInputStream pis = new PipedInputStream(pos);
53 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
54 |
55 | ProcessExecutor exec = new ProcessExecutor("java", "-cp", "target/test-classes", PrintInputToOutput.class.getName());
56 | exec.redirectInput(pis).redirectOutput(baos);
57 | StartedProcess startedProcess = exec.start();
58 | pos.write(str.getBytes());
59 | pos.write("\n\n\n".getBytes()); // PrintInputToOutput processes at most 3 lines
60 |
61 | // Assert that we don't get a TimeoutException
62 | startedProcess.getFuture().get(5, TimeUnit.SECONDS);
63 | Assert.assertEquals(str, baos.toString());
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorLoggerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.OutputStream;
21 |
22 | import org.junit.Assert;
23 | import org.junit.Test;
24 | import org.zeroturnaround.exec.ProcessExecutor;
25 | import org.zeroturnaround.exec.stream.PumpStreamHandler;
26 | import org.zeroturnaround.exec.stream.slf4j.Slf4jInfoOutputStream;
27 | import org.zeroturnaround.exec.stream.slf4j.Slf4jStream;
28 |
29 |
30 | public class ProcessExecutorLoggerTest {
31 |
32 | @Test
33 | public void testFullName() throws Exception {
34 | String fullName = "my.full.Logger";
35 | testSlf4jLoggerName(fullName, Slf4jStream.of(fullName));
36 | }
37 |
38 | @Test
39 | public void testShortName() throws Exception {
40 | String shortName = "MyLogger";
41 | String fullName = getClass().getName() + "." + shortName;
42 | testSlf4jLoggerName(fullName, Slf4jStream.of(shortName));
43 | }
44 |
45 | @Test
46 | public void testClassNameWithShortName() throws Exception {
47 | String shortName = "MyLogger";
48 | String fullName = getClass().getName() + "." + shortName;
49 | testSlf4jLoggerName(fullName, Slf4jStream.of(getClass(), shortName));
50 | }
51 |
52 | @Test
53 | public void testMyClassName() throws Exception {
54 | String fullName = getClass().getName();
55 | testSlf4jLoggerName(fullName, Slf4jStream.ofCaller());
56 | }
57 |
58 | private void testSlf4jLoggerName(String fullName, Slf4jStream stream) {
59 | ProcessExecutor executor = new ProcessExecutor();
60 | executor.redirectOutput(stream.asInfo());
61 | PumpStreamHandler pumps = executor.pumps();
62 | OutputStream out = pumps.getOut();
63 | Assert.assertTrue("Slf4jInfoOutputStream expected", out instanceof Slf4jInfoOutputStream);
64 | Assert.assertEquals(fullName, ((Slf4jInfoOutputStream) out).getLogger().getName());
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorMainTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.File;
21 | import java.io.IOException;
22 | import java.util.ArrayList;
23 | import java.util.Arrays;
24 | import java.util.List;
25 |
26 | import org.apache.commons.lang3.StringUtils;
27 | import org.junit.Assert;
28 | import org.junit.Test;
29 | import org.zeroturnaround.exec.ProcessExecutor;
30 | import org.zeroturnaround.exec.ProcessResult;
31 | import org.zeroturnaround.exec.stream.ExecuteStreamHandler;
32 | import org.zeroturnaround.exec.stream.slf4j.Slf4jStream;
33 |
34 |
35 | public class ProcessExecutorMainTest {
36 |
37 | @Test(expected=IllegalStateException.class)
38 | public void testNoCommand() throws Exception {
39 | new ProcessExecutor().execute();
40 | }
41 |
42 | @Test(expected=IOException.class)
43 | public void testNoSuchFile() throws Exception {
44 | new ProcessExecutor().command("unknown command").execute();
45 | }
46 |
47 | @Test
48 | public void testJavaVersion() throws Exception {
49 | int exit = new ProcessExecutor().command("java", "-version").execute().getExitValue();
50 | Assert.assertEquals(0, exit);
51 | }
52 |
53 | @Test
54 | public void testJavaVersionCommandSplit() throws Exception {
55 | int exit = new ProcessExecutor().commandSplit("java -version").execute().getExitValue();
56 | Assert.assertEquals(0, exit);
57 | }
58 |
59 | @Test
60 | public void testJavaVersionIterable() throws Exception {
61 | Iterable iterable = Arrays.asList("java", "-version");
62 | int exit = new ProcessExecutor().command(iterable).execute().getExitValue();
63 | Assert.assertEquals(0, exit);
64 | }
65 |
66 | @Test
67 | public void testJavaVersionFuture() throws Exception {
68 | int exit = new ProcessExecutor().command("java", "-version").start().getFuture().get().getExitValue();
69 | Assert.assertEquals(0, exit);
70 | }
71 |
72 | @Test
73 | public void testJavaVersionOutput() throws Exception {
74 | ProcessResult result = new ProcessExecutor().command("java", "-version").readOutput(true).execute();
75 | String str = result.outputUTF8();
76 | Assert.assertFalse(StringUtils.isEmpty(str));
77 | }
78 |
79 | @Test
80 | public void testJavaVersionOutputTwice() throws Exception {
81 | ProcessExecutor executor = new ProcessExecutor().command("java", "-version").readOutput(true);
82 | ProcessResult result = executor.execute();
83 | String str = result.outputUTF8();
84 | Assert.assertFalse(StringUtils.isEmpty(str));
85 | Assert.assertEquals(str, executor.execute().outputUTF8());
86 | }
87 |
88 | @Test
89 | public void testJavaVersionOutputFuture() throws Exception {
90 | ProcessResult result = new ProcessExecutor().command("java", "-version").readOutput(true).start().getFuture().get();
91 | String str = result.outputUTF8();
92 | Assert.assertFalse(StringUtils.isEmpty(str));
93 | }
94 |
95 | @Test
96 | public void testJavaVersionLogInfo() throws Exception {
97 | // Just expect no errors - don't check the log file itself
98 | new ProcessExecutor().command("java", "-version").redirectOutput(Slf4jStream.of("testJavaVersionLogInfo").asInfo()).execute();
99 | }
100 |
101 | @Test
102 | public void testJavaVersionLogInfoAndOutput() throws Exception {
103 | // Just expect no errors - don't check the log file itself
104 | ProcessResult result = new ProcessExecutor().command("java", "-version").redirectOutput(Slf4jStream.of("testJavaVersionLogInfoAndOutput").asInfo()).readOutput(true).execute();
105 | String str = result.outputUTF8();
106 | Assert.assertFalse(StringUtils.isEmpty(str));
107 | }
108 |
109 | @Test
110 | public void testJavaVersionLogInfoAndOutputFuture() throws Exception {
111 | // Just expect no errors - don't check the log file itself
112 | ProcessResult result = new ProcessExecutor().command("java", "-version").redirectOutput(Slf4jStream.of("testJavaVersionLogInfoAndOutputFuture").asInfo()).readOutput(true).start().getFuture().get();
113 | String str = result.outputUTF8();
114 | Assert.assertFalse(StringUtils.isEmpty(str));
115 | }
116 |
117 | @Test
118 | public void testJavaVersionNoStreams() throws Exception {
119 | // Just expect no errors
120 | new ProcessExecutor().command("java", "-version").streams(null).execute();
121 | }
122 |
123 | @Test
124 | public void testProcessDestroyerEvents() throws Exception {
125 | MockProcessDestroyer mock = new MockProcessDestroyer();
126 | new ProcessExecutor().command("java", "-version").destroyer(mock).execute();
127 | Assert.assertNotNull(mock.added);
128 | Assert.assertEquals(mock.added, mock.removed);
129 | }
130 |
131 | @Test
132 | public void testProcessDestroyerEventsOnStreamsFail() throws Exception {
133 | MockProcessDestroyer mock = new MockProcessDestroyer();
134 | ExecuteStreamHandler streams = new SetFailExecuteStreamHandler();
135 | try {
136 | new ProcessExecutor().command("java", "-version").streams(streams).destroyer(mock).execute();
137 | Assert.fail("IOException expected");
138 | }
139 | catch (IOException e) {
140 | // Good
141 | }
142 | Assert.assertNull(mock.added);
143 | Assert.assertNull(mock.removed);
144 | }
145 |
146 | @Test
147 | public void testProcessExecutorListInit() throws Exception {
148 | // Use timeout in case we get stuck
149 | List args = new ArrayList() {
150 | {
151 | add("java");
152 | add("-cp");
153 | add("target/test-classes");
154 | add(HelloWorld.class.getName());
155 | }
156 | };
157 | ProcessExecutor exec = new ProcessExecutor(args);
158 | ProcessResult result = exec.readOutput(true).execute();
159 | Assert.assertEquals("Hello world!", result.outputUTF8());
160 | }
161 |
162 | @Test
163 | public void testProcessExecutorCommand() throws Exception {
164 | // Use timeout in case we get stuck
165 | List args = new ArrayList() {
166 | {
167 | add("java");
168 | add("-cp");
169 | add("target/test-classes");
170 | add(HelloWorld.class.getName());
171 | }
172 | };
173 | ProcessExecutor exec = new ProcessExecutor();
174 | exec.command(args);
175 | ProcessResult result = exec.readOutput(true).execute();
176 | Assert.assertEquals("Hello world!", result.outputUTF8());
177 | }
178 |
179 | @Test
180 | public void testProcessExecutorSetDirectory() throws Exception {
181 | // Use timeout in case we get stuck
182 | List args = new ArrayList() {
183 | {
184 | add("java");
185 | add("-cp");
186 | add("test-classes");
187 | add(HelloWorld.class.getName());
188 | }
189 | };
190 | ProcessExecutor exec = new ProcessExecutor().directory(new File("target"));
191 | exec.command(args);
192 | ProcessResult result = exec.readOutput(true).execute();
193 | Assert.assertEquals("Hello world!", result.outputUTF8());
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorStreamCloseTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.ByteArrayOutputStream;
21 |
22 | import org.junit.Assert;
23 | import org.junit.Test;
24 | import org.zeroturnaround.exec.ProcessExecutor;
25 |
26 |
27 | /**
28 | * Tests that redirect target stream are not closed.
29 | *
30 | * @author Rein Raudjärv
31 | *
32 | * @see ProcessExecutor
33 | * @see HelloWorld
34 | */
35 | public class ProcessExecutorStreamCloseTest {
36 |
37 | @Test
38 | public void testRedirectOutputNotClosed() throws Exception {
39 | ByteArrayOutputStream out = new ByteArrayOutputStream();
40 | RememberCloseOutputStream close = new RememberCloseOutputStream(out);
41 | helloWorld().redirectOutput(close).redirectErrorStream(false).execute();
42 | Assert.assertEquals("Hello ", new String(out.toByteArray()));
43 | Assert.assertFalse(close.isClosed());
44 | }
45 |
46 | @Test
47 | public void testRedirectErrorNotClosed() throws Exception {
48 | ByteArrayOutputStream out = new ByteArrayOutputStream();
49 | RememberCloseOutputStream close = new RememberCloseOutputStream(out);
50 | helloWorld().redirectError(close).execute();
51 | Assert.assertEquals("world!", new String(out.toByteArray()));
52 | Assert.assertFalse(close.isClosed());
53 | }
54 |
55 | private ProcessExecutor helloWorld() {
56 | return new ProcessExecutor("java", "-cp", "target/test-classes", HelloWorld.class.getName());
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessExecutorTimeoutTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import org.apache.commons.lang3.SystemUtils;
21 | import org.hamcrest.CoreMatchers;
22 | import org.junit.Assert;
23 | import org.junit.Test;
24 | import org.zeroturnaround.exec.ProcessExecutor;
25 |
26 | import java.util.ArrayList;
27 | import java.util.List;
28 | import java.util.concurrent.TimeUnit;
29 | import java.util.concurrent.TimeoutException;
30 |
31 | public class ProcessExecutorTimeoutTest {
32 |
33 | @Test
34 | public void testExecuteTimeout() throws Exception {
35 | try {
36 | // Use timeout in case we get stuck
37 | List args = getWriterLoopCommand();
38 | new ProcessExecutor().command(args).timeout(1, TimeUnit.SECONDS).execute();
39 | Assert.fail("TimeoutException expected.");
40 | }
41 | catch (TimeoutException e) {
42 | Assert.assertThat(e.getMessage(), CoreMatchers.containsString("1 second"));
43 | Assert.assertThat(e.getMessage(), CoreMatchers.containsString(Loop.class.getName()));
44 | }
45 | }
46 |
47 | @Test
48 | public void testStartTimeout() throws Exception {
49 | try {
50 | // Use timeout in case we get stuck
51 | List args = getWriterLoopCommand();
52 | new ProcessExecutor().command(args).start().getFuture().get(1, TimeUnit.SECONDS);
53 | Assert.fail("TimeoutException expected.");
54 | }
55 | catch (TimeoutException e) {
56 | Assert.assertNull(e.getMessage());
57 | }
58 | }
59 |
60 | private List getWriterLoopCommand() {
61 | List args = new ArrayList() {
62 | {
63 | add("java");
64 | add("-cp");
65 | add("target/test-classes");
66 | add(Loop.class.getName());
67 | }
68 | };
69 | return args;
70 | }
71 |
72 | /*
73 | * This is a test copied from https://github.com/zeroturnaround/zt-exec/issues/56
74 | */
75 | @Test
76 | public void testExecuteTimeoutIssue56_1() throws Exception {
77 | try {
78 | List commands = new ArrayList();
79 | if (SystemUtils.IS_OS_WINDOWS) {
80 | // native sleep command is not available on Windows platform
81 | // mock using standard ping to localhost instead
82 | // (Windows ping does 4 requests which takes about 3 seconds)
83 | commands.add("ping");
84 | commands.add("127.0.0.1");
85 | }
86 | else {
87 | commands.add("sleep");
88 | commands.add("3");
89 | }
90 | new ProcessExecutor()
91 | .command(commands)
92 | .timeout(1, TimeUnit.SECONDS)
93 | .execute();
94 | Assert.fail("TimeoutException expected.");
95 | }
96 | catch (TimeoutException e) {
97 | Assert.assertThat(e.getMessage(), CoreMatchers.containsString("1 second"));
98 | }
99 | }
100 |
101 | /*
102 | * This is a test copied from https://github.com/zeroturnaround/zt-exec/issues/56
103 | */
104 | @Test
105 | public void testStartTimeoutIssue56_2() throws Exception {
106 | try {
107 | List commands = new ArrayList();
108 | if (SystemUtils.IS_OS_WINDOWS) {
109 | // native sleep command is not available on Windows platform
110 | // mock using standard ping to localhost instead
111 | // (Windows ping does 4 requests which takes about 3 seconds)
112 | commands.add("ping");
113 | commands.add("127.0.0.1");
114 | }
115 | else {
116 | commands.add("sleep");
117 | commands.add("3");
118 | }
119 | new ProcessExecutor()
120 | .command(commands)
121 | .start()
122 | .getFuture()
123 | .get(1, TimeUnit.SECONDS);
124 | Assert.fail("TimeoutException expected.");
125 | }
126 | catch (TimeoutException e) {
127 | Assert.assertNull(e.getMessage());
128 | }
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessInitExceptionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.IOException;
21 |
22 | import org.junit.Assert;
23 | import org.junit.Test;
24 | import org.zeroturnaround.exec.ProcessInitException;
25 |
26 | public class ProcessInitExceptionTest {
27 |
28 | @Test
29 | public void testNull() throws Exception {
30 | Assert.assertNull(ProcessInitException.newInstance(null, new IOException()));
31 | }
32 |
33 | @Test
34 | public void testEmpty() throws Exception {
35 | Assert.assertNull(ProcessInitException.newInstance(null, new IOException("")));
36 | }
37 |
38 | @Test
39 | public void testSimple() throws Exception {
40 | ProcessInitException e = ProcessInitException.newInstance(
41 | "Could not run test.", new IOException("java.io.IOException: Cannot run program \"ls\": java.io.IOException: error=12, Cannot allocate memory"));
42 | Assert.assertNotNull(e);
43 | Assert.assertEquals("Could not run test. Error=12, Cannot allocate memory", e.getMessage());
44 | Assert.assertEquals(12, e.getErrorCode());
45 | }
46 |
47 | @Test
48 | public void testBeforeCode() throws Exception {
49 | ProcessInitException e = ProcessInitException.newInstance(
50 | "Could not run test.", new IOException("java.io.IOException: Cannot run program \"sleep\": java.io.IOException: CreateProcess error=2, The system cannot find the file specified"));
51 | Assert.assertNotNull(e);
52 | Assert.assertEquals("Could not run test. Error=2, The system cannot find the file specified", e.getMessage());
53 | Assert.assertEquals(2, e.getErrorCode());
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessListenerSuccessTest.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.test;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 | import org.zeroturnaround.exec.ProcessExecutor;
6 | import org.zeroturnaround.exec.ProcessResult;
7 | import org.zeroturnaround.exec.listener.ProcessListener;
8 |
9 | public class ProcessListenerSuccessTest {
10 |
11 | @Test
12 | public void testJavaVersion() throws Exception {
13 | ProcessListenerImpl listener = new ProcessListenerImpl();
14 | ProcessResult result = new ProcessExecutor("java", "-version").addListener(listener).execute();
15 | int exit = result.getExitValue();
16 | Assert.assertEquals(0, exit);
17 | Assert.assertNotNull(listener.executor);
18 | Assert.assertNotNull(listener.process);
19 | Assert.assertNotNull(listener.result);
20 | Assert.assertEquals(result, listener.result);
21 | }
22 |
23 | static class ProcessListenerImpl extends ProcessListener {
24 |
25 | ProcessExecutor executor;
26 |
27 | Process process;
28 |
29 | ProcessResult result;
30 |
31 | @Override
32 | public void beforeStart(ProcessExecutor executor) {
33 | Assert.assertNotNull(executor);
34 |
35 | Assert.assertNull(this.executor);
36 | Assert.assertNull(this.process);
37 | Assert.assertNull(this.result);
38 |
39 | this.executor = executor;
40 | }
41 |
42 | @Override
43 | public void afterStart(Process process, ProcessExecutor executor) {
44 | Assert.assertNotNull(process);
45 | Assert.assertNotNull(executor);
46 |
47 | Assert.assertNotNull(this.executor);
48 | Assert.assertNull(this.process);
49 | Assert.assertNull(this.result);
50 |
51 | Assert.assertEquals(this.executor, executor);
52 | this.process = process;
53 | }
54 |
55 | @Override
56 | public void afterFinish(Process process, ProcessResult result) {
57 | Assert.assertNotNull(process);
58 | Assert.assertNotNull(result);
59 |
60 | Assert.assertNotNull(this.executor);
61 | Assert.assertNotNull(this.process);
62 | Assert.assertNull(this.result);
63 |
64 | Assert.assertEquals(this.process, process);
65 | this.result = result;
66 | }
67 |
68 | @Override
69 | public void afterStop(Process process) {
70 | Assert.assertNotNull(process);
71 |
72 | Assert.assertNotNull(this.executor);
73 | Assert.assertNotNull(this.process);
74 | Assert.assertNotNull(this.result);
75 |
76 | Assert.assertEquals(this.process, process);
77 | }
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/ProcessListenerThrowTest.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.test;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | import org.junit.Test;
6 | import org.zeroturnaround.exec.InvalidOutputException;
7 | import org.zeroturnaround.exec.ProcessExecutor;
8 | import org.zeroturnaround.exec.ProcessResult;
9 | import org.zeroturnaround.exec.test.ProcessListenerSuccessTest.ProcessListenerImpl;
10 |
11 | public class ProcessListenerThrowTest {
12 |
13 | @Test(expected=InvalidOutputException.class)
14 | public void testJavaVersion() throws Exception {
15 | new ProcessExecutor("java", "-version").readOutput(true).addListener(new ProcessListenerThrowImpl()).execute();
16 | }
17 |
18 | @Test(expected=InvalidOutputException.class)
19 | public void testJavaVersionWithTimeout() throws Exception {
20 | new ProcessExecutor("java", "-version").readOutput(true).addListener(new ProcessListenerThrowImpl()).timeout(1, TimeUnit.MINUTES).execute();
21 | }
22 |
23 | private static class ProcessListenerThrowImpl extends ProcessListenerImpl {
24 |
25 | @Override
26 | public void afterFinish(Process process, ProcessResult result) {
27 | super.afterFinish(process, result);
28 |
29 | if (result.getOutput().getString().contains("openjdk version") || result.getOutput().getString().contains("java version")) {
30 | throw new InvalidOutputException("Test", result);
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/RememberCloseOutputStream.java:
--------------------------------------------------------------------------------
1 | package org.zeroturnaround.exec.test;
2 |
3 | import java.io.FilterOutputStream;
4 | import java.io.IOException;
5 | import java.io.OutputStream;
6 |
7 | public class RememberCloseOutputStream extends FilterOutputStream {
8 |
9 | private volatile boolean closed;
10 |
11 | public RememberCloseOutputStream(OutputStream out) {
12 | super(out);
13 | }
14 |
15 | @Override
16 | public void close() throws IOException {
17 | closed = true;
18 | super.close();
19 | }
20 |
21 | public boolean isClosed() {
22 | return closed;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/SetFailExecuteStreamHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test;
19 |
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.io.OutputStream;
23 |
24 | import org.zeroturnaround.exec.stream.ExecuteStreamHandler;
25 |
26 |
27 | public class SetFailExecuteStreamHandler implements ExecuteStreamHandler {
28 |
29 | public void setProcessInputStream(OutputStream os) throws IOException {
30 | throw new IOException();
31 | }
32 |
33 | public void setProcessErrorStream(InputStream is) throws IOException {
34 | throw new IOException();
35 | }
36 |
37 | public void setProcessOutputStream(InputStream is) throws IOException {
38 | throw new IOException();
39 | }
40 |
41 | public void start() throws IOException {
42 | // do nothing
43 | }
44 |
45 | public void stop() {
46 | // do nothing
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/shutdown/ProcessExecutorShutdownHookTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test.shutdown;
19 |
20 | import java.io.File;
21 |
22 | import org.apache.commons.io.FileUtils;
23 | import org.apache.commons.lang3.SystemUtils;
24 | import org.junit.Assert;
25 | import org.junit.Test;
26 | import org.zeroturnaround.exec.ProcessExecutor;
27 |
28 |
29 | /**
30 | * Tests destroying processes on JVM exit.
31 | */
32 | public class ProcessExecutorShutdownHookTest {
33 |
34 | private static final long SLEEP_FOR_RECHECKING_FILE = 2000;
35 |
36 | @Test
37 | public void testDestroyOnExit() throws Exception {
38 | testDestroyOnExit(WriterLoopStarterBeforeExit.class, true);
39 | }
40 |
41 | @Test
42 | public void testDestroyOnExitInShutdownHook() throws Exception {
43 | testDestroyOnExit(WriterLoopStarterAfterExit.class, false);
44 | }
45 |
46 | private void testDestroyOnExit(Class> starter, boolean fileIsAlwaysCreated) throws Exception {
47 | File file = WriterLoop.getFile();
48 | if (file.exists())
49 | FileUtils.forceDelete(file);
50 | new ProcessExecutor("java", "-cp", SystemUtils.JAVA_CLASS_PATH, starter.getName()).redirectOutputAsInfo().execute();
51 | // After WriterLoopStarter has finished we expect that WriterLoop is also finished - no-one is updating the file
52 | if (fileIsAlwaysCreated || file.exists()) {
53 | checkFileStaysTheSame(file);
54 | FileUtils.forceDelete(file);
55 | }
56 | }
57 |
58 | private static void checkFileStaysTheSame(File file) throws InterruptedException {
59 | Assert.assertTrue(file.exists());
60 | long length = file.length();
61 | Thread.sleep(SLEEP_FOR_RECHECKING_FILE);
62 | Assert.assertEquals("File '" + file + "' was still updated.", length, file.length());
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/shutdown/WriterLoop.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test.shutdown;
19 |
20 | import java.io.File;
21 | import java.io.FileWriter;
22 | import java.io.PrintWriter;
23 |
24 | /**
25 | * Program which regularly writes into a file.
26 | * By checking whether the file gets updates we know whether this program is still running or it's finished.
27 | */
28 | class WriterLoop {
29 |
30 | private static final File FILE = new File("writeLoop.data");
31 |
32 | private static final long INTERVAL = 1000;
33 | private static final long COUNT = 10;
34 |
35 | public static File getFile() {
36 | return FILE;
37 | }
38 |
39 | public static void main(String[] args) throws Exception {
40 | PrintWriter out = new PrintWriter(new FileWriter(FILE), true);
41 | try {
42 | out.println("Started");
43 | for (int i = 0; i < COUNT; i++) {
44 | out.println(i);
45 | Thread.sleep(INTERVAL);
46 | }
47 | out.println("Finished");
48 | }
49 | finally {
50 | out.close();
51 | }
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/shutdown/WriterLoopStarterAfterExit.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test.shutdown;
19 |
20 | import org.zeroturnaround.exec.ProcessExecutor;
21 |
22 | /**
23 | * Starts {@link WriterLoop} inside shutdown hook and destroys it.
24 | */
25 | public class WriterLoopStarterAfterExit implements Runnable {
26 |
27 | private static final long SLEEP_AFTER_START = 2000;
28 |
29 | public static void main(String[] args) throws Exception {
30 | Runtime.getRuntime().addShutdownHook(new Thread(new WriterLoopStarterAfterExit()));
31 | // Launch the process and also destroy it
32 | System.exit(0);
33 | }
34 |
35 | public void run() {
36 | try {
37 | new ProcessExecutor("java", "-cp", "target/test-classes", WriterLoop.class.getName()).destroyOnExit().start();
38 | Thread.sleep(SLEEP_AFTER_START);
39 | }
40 | catch (Exception e) {
41 | e.printStackTrace();
42 | }
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/org/zeroturnaround/exec/test/shutdown/WriterLoopStarterBeforeExit.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 ZeroTurnaround
3 | * Contains fragments of code from Apache Commons Exec, rights owned
4 | * by Apache Software Foundation (ASF).
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package org.zeroturnaround.exec.test.shutdown;
19 |
20 | import org.zeroturnaround.exec.ProcessExecutor;
21 |
22 | /**
23 | * Starts {@link WriterLoop} and destroys it on JVM exit.
24 | */
25 | public class WriterLoopStarterBeforeExit {
26 |
27 | private static final long SLEEP_AFTER_START = 2000;
28 |
29 | public static void main(String[] args) throws Exception {
30 | new ProcessExecutor("java", "-cp", "target/test-classes", WriterLoop.class.getName()).destroyOnExit().start();
31 | Thread.sleep(SLEEP_AFTER_START);
32 | // Cause the launched process to be destroyed
33 | System.exit(0);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | target/test.log
5 | true
6 |
7 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{0}] %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------