Lines 52-57
Link Here
|
52 |
import java.io.OutputStream; |
52 |
import java.io.OutputStream; |
53 |
import java.io.OutputStreamWriter; |
53 |
import java.io.OutputStreamWriter; |
54 |
import java.io.Reader; |
54 |
import java.io.Reader; |
|
|
55 |
import java.io.Writer; |
55 |
import java.nio.charset.Charset; |
56 |
import java.nio.charset.Charset; |
56 |
import java.security.AccessController; |
57 |
import java.security.AccessController; |
57 |
import java.security.PrivilegedAction; |
58 |
import java.security.PrivilegedAction; |
Lines 66-75
Link Here
|
66 |
import java.util.concurrent.Future; |
67 |
import java.util.concurrent.Future; |
67 |
import java.util.concurrent.FutureTask; |
68 |
import java.util.concurrent.FutureTask; |
68 |
import java.util.concurrent.TimeUnit; |
69 |
import java.util.concurrent.TimeUnit; |
|
|
70 |
import java.util.concurrent.atomic.AtomicInteger; |
69 |
import java.util.logging.Level; |
71 |
import java.util.logging.Level; |
70 |
import java.util.logging.Logger; |
72 |
import java.util.logging.Logger; |
71 |
import javax.swing.AbstractAction; |
73 |
import javax.swing.AbstractAction; |
72 |
import org.netbeans.api.annotations.common.NonNull; |
74 |
import org.netbeans.api.annotations.common.NonNull; |
|
|
75 |
import org.netbeans.api.annotations.common.NullAllowed; |
73 |
import org.netbeans.api.progress.ProgressHandle; |
76 |
import org.netbeans.api.progress.ProgressHandle; |
74 |
import org.netbeans.api.progress.ProgressHandleFactory; |
77 |
import org.netbeans.api.progress.ProgressHandleFactory; |
75 |
import org.netbeans.modules.extexecution.ProcessInputStream; |
78 |
import org.netbeans.modules.extexecution.ProcessInputStream; |
Lines 79-85
Link Here
|
79 |
import org.netbeans.api.extexecution.input.InputProcessors; |
82 |
import org.netbeans.api.extexecution.input.InputProcessors; |
80 |
import org.netbeans.api.extexecution.input.InputReaderTask; |
83 |
import org.netbeans.api.extexecution.input.InputReaderTask; |
81 |
import org.netbeans.api.extexecution.input.InputReaders; |
84 |
import org.netbeans.api.extexecution.input.InputReaders; |
|
|
85 |
import org.netbeans.api.extexecution.input.LineProcessor; |
82 |
import org.netbeans.api.extexecution.input.LineProcessors; |
86 |
import org.netbeans.api.extexecution.input.LineProcessors; |
|
|
87 |
import org.netbeans.api.extexecution.process.ProcessCharset; |
83 |
import org.openide.util.Cancellable; |
88 |
import org.openide.util.Cancellable; |
84 |
import org.openide.util.Mutex; |
89 |
import org.openide.util.Mutex; |
85 |
import org.openide.util.NbBundle; |
90 |
import org.openide.util.NbBundle; |
Lines 91-110
Link Here
|
91 |
* Execution service provides the facility to execute the process while |
96 |
* Execution service provides the facility to execute the process while |
92 |
* displaying the output and handling the input. |
97 |
* displaying the output and handling the input. |
93 |
* <p> |
98 |
* <p> |
94 |
* It will execute the program with an associated I/O window, with stop and |
99 |
* It will execute the program with an associated I/O window, possibly with |
95 |
* restart buttons. It will also obey various descriptor properties such as |
100 |
* stop and restart buttons. It will also obey various descriptor properties |
96 |
* whether or not to show a progress bar. |
101 |
* such as whether or not to show a progress bar. |
97 |
* <p> |
102 |
* <p> |
98 |
* All processes launched by this class are terminated on VM exit (if |
103 |
* All processes launched by this class are terminated on VM exit (if |
99 |
* these are not finished or terminated earlier). |
104 |
* these are not finished or terminated earlier). |
100 |
* <p> |
105 |
* <p> |
101 |
* Note that once service is run for the first time, subsequents runs can be |
106 |
* Note that once service is run for the first time, subsequent runs can be |
102 |
* invoked by the user (rerun button) if it is allowed to do so |
107 |
* invoked by the user (rerun button) if it is allowed to do so |
103 |
* ({@link ExecutionDescriptor#isControllable()}). |
108 |
* ({@link ExecutionDescriptor#isControllable()}). |
104 |
* |
109 |
* |
105 |
* <div class="nonnormative"> |
110 |
* <div class="nonnormative"> |
106 |
* <p> |
111 |
* <p> |
107 |
* Sample usage - executing ls command: |
112 |
* Sample usage (ls command): |
108 |
* <pre> |
113 |
* <pre> |
109 |
* ExecutionDescriptor descriptor = new ExecutionDescriptor() |
114 |
* ExecutionDescriptor descriptor = new ExecutionDescriptor() |
110 |
* .frontWindow(true).controllable(true); |
115 |
* .frontWindow(true).controllable(true); |
Lines 114-119
Link Here
|
114 |
* ExecutionService service = ExecutionService.newService(processBuilder, descriptor, "ls command"); |
119 |
* ExecutionService service = ExecutionService.newService(processBuilder, descriptor, "ls command"); |
115 |
* Future<Integer> task = service.run(); |
120 |
* Future<Integer> task = service.run(); |
116 |
* </pre> |
121 |
* </pre> |
|
|
122 |
* <p> |
123 |
* Even simpler usage but without displaying output (ls command): |
124 |
* <pre> |
125 |
* ExternalProcessBuilder processBuilder = new ExternalProcessBuilder("ls"); |
126 |
* |
127 |
* ExecutionService service = ExecutionService.newService(processBuilder, null, null); |
128 |
* Future<Integer> task = service.run(); |
129 |
* </pre> |
117 |
* </div> |
130 |
* </div> |
118 |
* |
131 |
* |
119 |
* @author Petr Hejl |
132 |
* @author Petr Hejl |
Lines 130-135
Link Here
|
130 |
|
143 |
|
131 |
private static final ExecutorService EXECUTOR_SERVICE = new RequestProcessor(ExecutionService.class.getName(), Integer.MAX_VALUE); |
144 |
private static final ExecutorService EXECUTOR_SERVICE = new RequestProcessor(ExecutionService.class.getName(), Integer.MAX_VALUE); |
132 |
|
145 |
|
|
|
146 |
private static final InputProcessor NULL_PROCESSOR = new InputProcessor() { |
147 |
|
148 |
@Override |
149 |
public void processInput(char[] chars) throws IOException { |
150 |
} |
151 |
|
152 |
@Override |
153 |
public void reset() throws IOException { |
154 |
} |
155 |
|
156 |
@Override |
157 |
public void close() throws IOException { |
158 |
} |
159 |
}; |
160 |
|
133 |
static { |
161 |
static { |
134 |
// rerun accessor |
162 |
// rerun accessor |
135 |
RerunAction.Accessor.setDefault(new RerunAction.Accessor() { |
163 |
RerunAction.Accessor.setDefault(new RerunAction.Accessor() { |
Lines 156-171
Link Here
|
156 |
}); |
184 |
}); |
157 |
} |
185 |
} |
158 |
|
186 |
|
159 |
private final Callable<Process> processCreator; |
187 |
private final Callable<? extends Process> processCreator; |
160 |
|
188 |
|
161 |
private final ExecutionDescriptor descriptor; |
189 |
private final ExecutionDescriptor descriptor; |
162 |
|
190 |
|
163 |
private final String originalDisplayName; |
191 |
private final String originalDisplayName; |
164 |
|
192 |
|
165 |
private ExecutionService(Callable<Process> processCreator, String displayName, ExecutionDescriptor descriptor) { |
193 |
private final Reader processInput; |
|
|
194 |
|
195 |
private final boolean rerunAllowed; |
196 |
|
197 |
private final AtomicInteger runCount = new AtomicInteger(); |
198 |
|
199 |
private ExecutionService(Callable<? extends Process> processCreator, String displayName, |
200 |
ExecutionDescriptor descriptor, Reader processInput, boolean rerunAllowed) { |
166 |
this.processCreator = processCreator; |
201 |
this.processCreator = processCreator; |
167 |
this.originalDisplayName = displayName; |
202 |
this.originalDisplayName = displayName; |
168 |
this.descriptor = descriptor; |
203 |
this.descriptor = descriptor; |
|
|
204 |
this.processInput = processInput; |
205 |
this.rerunAllowed = rerunAllowed; |
169 |
} |
206 |
} |
170 |
|
207 |
|
171 |
/** |
208 |
/** |
Lines 178-201
Link Here
|
178 |
* @return new execution service |
215 |
* @return new execution service |
179 |
*/ |
216 |
*/ |
180 |
@NonNull |
217 |
@NonNull |
181 |
public static ExecutionService newService(@NonNull Callable<Process> processCreator, |
218 |
public static ExecutionService newService(@NonNull Callable<? extends Process> processCreator, |
182 |
@NonNull ExecutionDescriptor descriptor, @NonNull String displayName) { |
219 |
@NonNull ExecutionDescriptor descriptor, @NonNull String displayName) { |
183 |
return new ExecutionService(processCreator, displayName, descriptor); |
220 |
return new ExecutionService(processCreator, displayName, descriptor, null, true); |
|
|
221 |
} |
222 |
|
223 |
/** |
224 |
* Creates new execution service. Service will wrap up the processes |
225 |
* created by <code>processCreator</code> and will manage them. The service |
226 |
* <i>may not</i> be run more than once otherwise {@link IllegalStateException} |
227 |
* is thrown on {@link #run()}. No UI will be displayed. |
228 |
* <p> |
229 |
* Passed processInput will be implicitly closed when the execution (invoked by |
230 |
* {@link #run()}) is finished. The client should not use the reader passed |
231 |
* as argument anymore or the reader should be designed thread safe. |
232 |
* |
233 |
* @param processCreator callable returning the process to wrap up |
234 |
* @param outputProcessor processor processing lines of standard output; |
235 |
* may be <code>null</code> |
236 |
* @param errorProcessor processor processing lines of standard error |
237 |
* output; may be <code>null</code> |
238 |
* @param processorInput reader providing input for standard input of |
239 |
* the created process. Once passed it either should not be |
240 |
* used anymore or it should be designed to be thread safe. |
241 |
* May be <code>null</code>. |
242 |
* @return new execution service |
243 |
* @since 1.37 |
244 |
*/ |
245 |
@NonNull |
246 |
public static ExecutionService newService(@NonNull Callable<? extends Process> processCreator, |
247 |
@NullAllowed final LineProcessor outputProcessor, @NullAllowed final LineProcessor errorProcessor, |
248 |
@NullAllowed final Reader processorInput) { |
249 |
ExecutionDescriptor descriptor = new ExecutionDescriptor() |
250 |
.inputOutput(InputOutput.NULL); |
251 |
|
252 |
if (outputProcessor != null) { |
253 |
descriptor = descriptor.outProcessorFactory(new InputProcessorFactory() { |
254 |
@Override |
255 |
public InputProcessor newInputProcessor(InputProcessor defaultProcessor) { |
256 |
return InputProcessors.bridge(outputProcessor); |
257 |
} |
258 |
}); |
259 |
} |
260 |
if (errorProcessor != null) { |
261 |
descriptor = descriptor.errProcessorFactory(new InputProcessorFactory() { |
262 |
@Override |
263 |
public InputProcessor newInputProcessor(InputProcessor defaultProcessor) { |
264 |
return InputProcessors.bridge(errorProcessor); |
265 |
} |
266 |
}); |
267 |
} |
268 |
|
269 |
return new ExecutionService(processCreator, null, descriptor, processorInput, false); |
270 |
} |
271 |
|
272 |
/** |
273 |
* Creates new execution service. Service will wrap up the processes |
274 |
* created by <code>processCreator</code> and will manage them. The service |
275 |
* <i>may not</i> be run more than once otherwise {@link IllegalStateException} |
276 |
* is thrown on {@link #run()}. No UI will be displayed. |
277 |
* <p> |
278 |
* Passed inputWriter and errorWriter will be implicitly closed when the |
279 |
* execution (invoked by {@link #run()}) is finished. The client either |
280 |
* <i>should not use the passed writers anymore or these should be designed |
281 |
* to be thread safe</i>. |
282 |
* |
283 |
* @param processCreator callable returning the process to wrap up |
284 |
* @param outputWriter where to write standard output of the process. Once |
285 |
* passed it either should not be used anymore or it should |
286 |
* be designed to be thread safe. May be <code>null</code>. |
287 |
* @param errorWriter where to write standard error output of the process. |
288 |
* Once passed it either should not be used anymore or it should |
289 |
* be designed to be thread safe. May be <code>null</code>. |
290 |
* @return new execution service |
291 |
* @since 1.37 |
292 |
*/ |
293 |
public static ExecutionService newService(@NonNull Callable<? extends Process> processCreator, |
294 |
@NullAllowed final Writer outputWriter, @NullAllowed final Writer errorWriter) { |
295 |
ExecutionDescriptor descriptor = new ExecutionDescriptor() |
296 |
.inputOutput(InputOutput.NULL); |
297 |
|
298 |
if (outputWriter != null) { |
299 |
descriptor = descriptor.outProcessorFactory(new InputProcessorFactory() { |
300 |
@Override |
301 |
public InputProcessor newInputProcessor(InputProcessor defaultProcessor) { |
302 |
return InputProcessors.copying(outputWriter); |
303 |
} |
304 |
}); |
305 |
} |
306 |
if (errorWriter != null) { |
307 |
descriptor = descriptor.errProcessorFactory(new InputProcessorFactory() { |
308 |
@Override |
309 |
public InputProcessor newInputProcessor(InputProcessor defaultProcessor) { |
310 |
return InputProcessors.copying(errorWriter); |
311 |
} |
312 |
}); |
313 |
} |
314 |
|
315 |
return new ExecutionService(processCreator, null, descriptor, null, false); |
184 |
} |
316 |
} |
185 |
|
317 |
|
186 |
/** |
318 |
/** |
187 |
* Runs the process described by this service. The call does not block |
319 |
* Runs the process described by this service. The call does not block |
188 |
* and the task is represented by the returned value. Integer returned |
320 |
* and the task is represented by the returned value. Integer returned |
189 |
* as a result of the {@link Future} is exit code of the process. |
321 |
* as a result of the {@link Future} is exit code of the process. |
|
|
322 |
* The ability to call this method multiple times depends on a way |
323 |
* in which the service has been created. Only service created by |
324 |
* {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.ExecutionDescriptor, java.lang.String)} |
325 |
* may be run more than once. |
190 |
* <p> |
326 |
* <p> |
191 |
* The output tabs are reused (if caller does not use the custom one, |
327 |
* The output tabs are reused (if caller does not use the custom one, |
192 |
* see {@link ExecutionDescriptor#getInputOutput()}) - the tab to reuse |
328 |
* see {@link ExecutionDescriptor#getInputOutput()} or if it is not being |
193 |
* (if any) is selected by having the same name and same buttons |
329 |
* run without output tab, see {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.input.LineProcessor, org.netbeans.api.extexecution.input.LineProcessor, java.io.Reader)}) |
194 |
* (control and option). If there is no output tab to reuse new one |
330 |
* - the tab to reuse (if any) is selected by having the same name |
195 |
* is opened. |
331 |
* and same buttons (control and option). If there is no output tab to |
|
|
332 |
* reuse new one is opened. |
196 |
* <p> |
333 |
* <p> |
197 |
* This method can be invoked multiple times returning the different and |
334 |
* If the service has been created by {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.input.LineProcessor, org.netbeans.api.extexecution.input.LineProcessor, java.io.Reader)} |
198 |
* unrelated {@link Future}s. On each call <code>Callable<Process></code> |
335 |
* this method may be called only once. Subsequent calls will cause an |
|
|
336 |
* {@link IllegalStateException} to be thrown. |
337 |
* If the service has been created by {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.ExecutionDescriptor, java.lang.String)} |
338 |
* this method can be invoked multiple times returning the different and |
339 |
* unrelated {@link Future}s. |
340 |
* <p> |
341 |
* On each call <code>Callable<Process></code> |
199 |
* passed to {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.ExecutionDescriptor, java.lang.String)} |
342 |
* passed to {@link #newService(java.util.concurrent.Callable, org.netbeans.api.extexecution.ExecutionDescriptor, java.lang.String)} |
200 |
* is invoked in order to create the process. If the process creation fails |
343 |
* is invoked in order to create the process. If the process creation fails |
201 |
* (throwing an exception) returned <code>Future</code> will throw |
344 |
* (throwing an exception) returned <code>Future</code> will throw |
Lines 213-218
Link Here
|
213 |
} |
356 |
} |
214 |
|
357 |
|
215 |
private Future<Integer> run(InputOutput required) { |
358 |
private Future<Integer> run(InputOutput required) { |
|
|
359 |
if (!rerunAllowed && runCount.incrementAndGet() > 1) { |
360 |
throw new IllegalStateException("Run invoked multimple times"); |
361 |
} |
362 |
|
216 |
final InputOutputManager.InputOutputData ioData = getInputOutput(required); |
363 |
final InputOutputManager.InputOutputData ioData = getInputOutput(required); |
217 |
|
364 |
|
218 |
final String displayName = ioData.getDisplayName(); |
365 |
final String displayName = ioData.getDisplayName(); |
Lines 220-228
Link Here
|
220 |
final ProgressHandle handle = createProgressHandle(ioData.getInputOutput(), displayName, cancellable); |
367 |
final ProgressHandle handle = createProgressHandle(ioData.getInputOutput(), displayName, cancellable); |
221 |
final InputOutput io = ioData.getInputOutput(); |
368 |
final InputOutput io = ioData.getInputOutput(); |
222 |
|
369 |
|
223 |
final OutputWriter out = io.getOut(); |
370 |
assert processInput == null || io == InputOutput.NULL; |
224 |
final OutputWriter err = io.getErr(); |
371 |
|
225 |
final Reader in = io.getIn(); |
372 |
final Reader in; |
|
|
373 |
if (processInput != null) { |
374 |
in = processInput; |
375 |
} else if (descriptor.isInputVisible() && io != InputOutput.NULL) { |
376 |
in = io.getIn(); |
377 |
} else { |
378 |
in = null; |
379 |
} |
226 |
|
380 |
|
227 |
final CountDownLatch finishedLatch = new CountDownLatch(1); |
381 |
final CountDownLatch finishedLatch = new CountDownLatch(1); |
228 |
|
382 |
|
Lines 267-289
Link Here
|
267 |
outStream = new ProcessInputStream(process, process.getInputStream()); |
421 |
outStream = new ProcessInputStream(process, process.getInputStream()); |
268 |
errStream = new ProcessInputStream(process, process.getErrorStream()); |
422 |
errStream = new ProcessInputStream(process, process.getErrorStream()); |
269 |
|
423 |
|
270 |
executor = Executors.newFixedThreadPool(descriptor.isInputVisible() ? 3 : 2); |
424 |
executor = Executors.newFixedThreadPool(in != null ? 3 : 2); |
271 |
|
425 |
|
272 |
Charset charset = descriptor.getCharset(); |
426 |
Charset charset = descriptor.getCharset(); |
|
|
427 |
Charset inputCharset = charset; |
428 |
Charset outputCharset = charset; |
429 |
Charset errorCharset = charset; |
273 |
if (charset == null) { |
430 |
if (charset == null) { |
274 |
charset = Charset.defaultCharset(); |
431 |
inputCharset = ProcessCharset.getInputCharset(process); |
|
|
432 |
outputCharset = ProcessCharset.getOutputCharset(process); |
433 |
errorCharset = ProcessCharset.getErrorCharset(process); |
434 |
} |
435 |
if (inputCharset == null) { |
436 |
inputCharset = Charset.defaultCharset(); |
437 |
} |
438 |
if (outputCharset == null) { |
439 |
outputCharset = Charset.defaultCharset(); |
440 |
} |
441 |
if (errorCharset == null) { |
442 |
errorCharset = Charset.defaultCharset(); |
275 |
} |
443 |
} |
276 |
|
444 |
|
277 |
tasks.add(InputReaderTask.newDrainingTask( |
445 |
tasks.add(InputReaderTask.newDrainingTask( |
278 |
InputReaders.forStream(new BufferedInputStream(outStream), charset), |
446 |
InputReaders.forStream(new BufferedInputStream(outStream), outputCharset), |
279 |
createOutProcessor(out))); |
447 |
createOutProcessor(io))); |
280 |
tasks.add(InputReaderTask.newDrainingTask( |
448 |
tasks.add(InputReaderTask.newDrainingTask( |
281 |
InputReaders.forStream(new BufferedInputStream(errStream), charset), |
449 |
InputReaders.forStream(new BufferedInputStream(errStream), errorCharset), |
282 |
createErrProcessor(err))); |
450 |
createErrProcessor(io))); |
283 |
if (descriptor.isInputVisible()) { |
451 |
if (in != null) { |
284 |
tasks.add(InputReaderTask.newTask( |
452 |
tasks.add(InputReaderTask.newTask( |
285 |
InputReaders.forReader(in), |
453 |
InputReaders.forReader(in), |
286 |
createInProcessor(process.getOutputStream()))); |
454 |
createInProcessor(process.getOutputStream(), inputCharset))); |
287 |
} |
455 |
} |
288 |
for (InputReaderTask task : tasks) { |
456 |
for (InputReaderTask task : tasks) { |
289 |
executor.submit(task); |
457 |
executor.submit(task); |
Lines 568-582
Link Here
|
568 |
Mutex.EVENT.readAccess(ui); |
736 |
Mutex.EVENT.readAccess(ui); |
569 |
} |
737 |
} |
570 |
|
738 |
|
571 |
private InputProcessor createOutProcessor(OutputWriter writer) { |
739 |
private InputProcessor createOutProcessor(InputOutput io) { |
572 |
LineConvertorFactory convertorFactory = descriptor.getOutConvertorFactory(); |
|
|
573 |
InputProcessor outProcessor = null; |
740 |
InputProcessor outProcessor = null; |
574 |
if (descriptor.isOutLineBased()) { |
741 |
if (io != InputOutput.NULL) { |
575 |
outProcessor = InputProcessors.bridge(LineProcessors.printing(writer, |
742 |
LineConvertorFactory convertorFactory = descriptor.getOutConvertorFactory(); |
576 |
convertorFactory != null ? convertorFactory.newLineConvertor() : null, true)); |
743 |
OutputWriter writer = io.getOut(); |
|
|
744 |
if (descriptor.isOutLineBased()) { |
745 |
outProcessor = InputProcessors.bridge(LineProcessors.printing(writer, |
746 |
convertorFactory != null ? convertorFactory.newLineConvertor() : null, true)); |
747 |
} else { |
748 |
outProcessor = InputProcessors.printing(writer, |
749 |
convertorFactory != null ? convertorFactory.newLineConvertor() : null, true); |
750 |
} |
577 |
} else { |
751 |
} else { |
578 |
outProcessor = InputProcessors.printing(writer, |
752 |
outProcessor = NULL_PROCESSOR; |
579 |
convertorFactory != null ? convertorFactory.newLineConvertor() : null, true); |
|
|
580 |
} |
753 |
} |
581 |
|
754 |
|
582 |
InputProcessorFactory descriptorOutFactory = descriptor.getOutProcessorFactory(); |
755 |
InputProcessorFactory descriptorOutFactory = descriptor.getOutProcessorFactory(); |
Lines 587-601
Link Here
|
587 |
return outProcessor; |
760 |
return outProcessor; |
588 |
} |
761 |
} |
589 |
|
762 |
|
590 |
private InputProcessor createErrProcessor(OutputWriter writer) { |
763 |
private InputProcessor createErrProcessor(InputOutput io) { |
591 |
LineConvertorFactory convertorFactory = descriptor.getErrConvertorFactory(); |
|
|
592 |
InputProcessor errProcessor = null; |
764 |
InputProcessor errProcessor = null; |
593 |
if (descriptor.isErrLineBased()) { |
765 |
if (io != InputOutput.NULL) { |
594 |
errProcessor = InputProcessors.bridge(LineProcessors.printing(writer, |
766 |
LineConvertorFactory convertorFactory = descriptor.getErrConvertorFactory(); |
595 |
convertorFactory != null ? convertorFactory.newLineConvertor() : null, false)); |
767 |
OutputWriter writer = io.getErr(); |
|
|
768 |
if (descriptor.isErrLineBased()) { |
769 |
errProcessor = InputProcessors.bridge(LineProcessors.printing(writer, |
770 |
convertorFactory != null ? convertorFactory.newLineConvertor() : null, false)); |
771 |
} else { |
772 |
errProcessor = InputProcessors.printing(writer, |
773 |
convertorFactory != null ? convertorFactory.newLineConvertor() : null, false); |
774 |
} |
596 |
} else { |
775 |
} else { |
597 |
errProcessor = InputProcessors.printing(writer, |
776 |
errProcessor = NULL_PROCESSOR; |
598 |
convertorFactory != null ? convertorFactory.newLineConvertor() : null, false); |
|
|
599 |
} |
777 |
} |
600 |
|
778 |
|
601 |
InputProcessorFactory descriptorErrFactory = descriptor.getErrProcessorFactory(); |
779 |
InputProcessorFactory descriptorErrFactory = descriptor.getErrProcessorFactory(); |
Lines 606-613
Link Here
|
606 |
return errProcessor; |
784 |
return errProcessor; |
607 |
} |
785 |
} |
608 |
|
786 |
|
609 |
private InputProcessor createInProcessor(OutputStream os) { |
787 |
private InputProcessor createInProcessor(OutputStream os, Charset charset) { |
610 |
return InputProcessors.copying(new OutputStreamWriter(os)); |
788 |
return InputProcessors.copying(new OutputStreamWriter(os, charset)); |
611 |
} |
789 |
} |
612 |
|
790 |
|
613 |
private static class ProgressCancellable implements Cancellable { |
791 |
private static class ProgressCancellable implements Cancellable { |