OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 80 | Rev 156 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.utils;
15
 
16
import java.io.BufferedReader;
17
import java.io.IOException;
18
import java.io.InputStream;
19
import java.io.InputStreamReader;
93 ilm 20
import java.io.OutputStream;
17 ilm 21
import java.io.PrintStream;
22
import java.util.concurrent.Callable;
23
import java.util.concurrent.CountDownLatch;
24
import java.util.concurrent.ExecutorService;
25
import java.util.concurrent.Executors;
26
import java.util.concurrent.Future;
27
 
28
/**
29
 * Redirect streams of a process to System.out and System.err.
30
 *
31
 * @author Sylvain
32
 */
33
public class ProcessStreams {
34
 
80 ilm 35
    static public enum Action {
36
        /**
37
         * Redirect process streams to ours.
38
         */
39
        REDIRECT,
40
        /**
93 ilm 41
         * Consume streams.
80 ilm 42
         */
93 ilm 43
        CONSUME,
44
        /**
45
         * Close process streams. NOTE : some programs might fail (e.g. route on FreeBSD), in those
46
         * cases use {@link #CONSUME}.
47
         */
80 ilm 48
        CLOSE,
49
        /**
50
         * Do nothing, which is dangerous as the process will hang until its output is read.
51
         */
52
        DO_NOTHING
53
    }
54
 
55
    static public final Process handle(final Process p, final Action action) throws IOException {
56
        if (action == Action.CLOSE) {
57
            p.getInputStream().close();
58
            p.getErrorStream().close();
59
        } else if (action == Action.REDIRECT) {
60
            new ProcessStreams(p);
93 ilm 61
        } else if (action == Action.CONSUME) {
62
            new ProcessStreams(p, StreamUtils.NULL_OS, StreamUtils.NULL_OS);
80 ilm 63
        }
64
        return p;
65
    }
66
 
17 ilm 67
    private final ExecutorService exec = Executors.newFixedThreadPool(2);
68
    private final CountDownLatch latch;
69
    private final Future<?> out;
70
    private final Future<?> err;
71
 
72
    public ProcessStreams(final Process p) {
93 ilm 73
        this(p, System.out, System.err);
74
    }
75
 
76
    /**
77
     * Create a new instance and start reading from the passed process. If a passed
78
     * {@link OutputStream} is <code>null</code>, then the corresponding {@link InputStream} is not
79
     * used at all, so the caller should handle it. If the output must be discarded, use
80
     * {@link StreamUtils#NULL_OS}.
81
     *
82
     * @param p the process to read from.
83
     * @param out where to write the {@link Process#getInputStream() standard output}.
84
     * @param err where to write the {@link Process#getErrorStream() standard error}.
85
     */
86
    public ProcessStreams(final Process p, final OutputStream out, final OutputStream err) {
17 ilm 87
        this.latch = new CountDownLatch(2);
93 ilm 88
        this.out = writeToAsync(p.getInputStream(), out);
89
        this.err = writeToAsync(p.getErrorStream(), err);
80 ilm 90
        this.exec.submit(new Runnable() {
17 ilm 91
            public void run() {
92
                try {
93
                    ProcessStreams.this.latch.await();
94
                } catch (InterruptedException e) {
95
                    // ne rien faire
96
                    e.printStackTrace();
97
                } finally {
98
                    ProcessStreams.this.exec.shutdown();
99
                }
100
            }
80 ilm 101
        });
17 ilm 102
    }
103
 
104
    protected final void stopOut() {
105
        this.stop(this.out);
106
    }
107
 
108
    protected final void stopErr() {
109
        this.stop(this.err);
110
    }
111
 
112
    private final void stop(Future<?> f) {
93 ilm 113
        if (f == null)
114
            return;
17 ilm 115
        // TODO
116
        // ATTN don't interrupt, hangs in readLine()
117
        f.cancel(false);
118
    }
119
 
93 ilm 120
    private final Future<?> writeToAsync(final InputStream ins, final Object outs) {
121
        if (outs == null) {
122
            this.latch.countDown();
123
            return null;
124
        }
17 ilm 125
        return this.exec.submit(new Callable<Object>() {
126
            public Object call() throws InterruptedException, IOException {
127
                try {
93 ilm 128
                    // PrintStream is also an OutputStream
129
                    if (outs instanceof PrintStream)
130
                        writeTo(ins, (PrintStream) outs);
131
                    else
132
                        StreamUtils.copy(ins, (OutputStream) outs);
133
                    ins.close();
17 ilm 134
                    return null;
135
                } finally {
136
                    ProcessStreams.this.latch.countDown();
137
                }
138
            }
139
        });
140
    }
141
 
142
    /**
143
     * Copy ins to outs, line by line.
144
     *
145
     * @param ins the source.
146
     * @param outs the destination.
147
     * @throws InterruptedException if current thread is interrupted.
93 ilm 148
     * @throws IOException if I/O error.
17 ilm 149
     */
150
    public static final void writeTo(InputStream ins, PrintStream outs) throws InterruptedException, IOException {
151
        final BufferedReader r = new BufferedReader(new InputStreamReader(ins));
152
        String encodedName;
153
        while ((encodedName = r.readLine()) != null) {
154
            if (Thread.currentThread().isInterrupted()) {
155
                throw new InterruptedException();
156
            }
157
            outs.println(encodedName);
158
        }
159
    }
160
 
161
}