source: java/main/src/main/java/com/framsticks/running/ExternalProcess.java @ 193

Last change on this file since 193 was 193, checked in by Maciej Komosinski, 10 years ago

Set svn:eol-style native for all textual files

  • Property svn:eol-style set to native
File size: 6.2 KB
RevLine 
[88]1package com.framsticks.running;
2
3import java.io.BufferedReader;
4import java.io.File;
5import java.io.IOException;
6import java.io.InputStreamReader;
7import java.io.OutputStreamWriter;
8import java.io.PrintWriter;
9import java.util.ArrayList;
[107]10import java.util.Arrays;
[88]11import java.util.List;
12
13
[100]14import org.apache.logging.log4j.Logger;
15import org.apache.logging.log4j.LogManager;
[88]16
[101]17import com.framsticks.params.EventListener;
18import com.framsticks.params.EventListeners;
19import com.framsticks.params.ParamFlags;
[90]20import com.framsticks.params.annotations.AutoAppendAnnotation;
[88]21import com.framsticks.params.annotations.FramsClassAnnotation;
22import com.framsticks.params.annotations.ParamAnnotation;
[105]23import com.framsticks.structure.messages.ValueChange;
[88]24import com.framsticks.util.FramsticksException;
[90]25import com.framsticks.util.dispatching.AbstractJoinable;
26import com.framsticks.util.dispatching.Dispatching;
27import com.framsticks.util.dispatching.Joinable;
28import com.framsticks.util.dispatching.JoinableParent;
29import com.framsticks.util.dispatching.JoinableState;
30import com.framsticks.util.dispatching.RunAt;
[88]31import com.framsticks.util.dispatching.Thread;
[97]32import com.framsticks.util.dispatching.ThrowExceptionHandler;
[88]33import com.framsticks.util.io.Encoding;
[107]34import com.framsticks.util.lang.Strings;
[88]35
36@FramsClassAnnotation
[96]37public class ExternalProcess extends AbstractJoinable implements JoinableParent {
[100]38        private static final Logger log = LogManager.getLogger(ExternalProcess.class);
[88]39
40        protected List<String> arguments = new ArrayList<>();
41        protected Process process;
[90]42        protected Thread<ExternalProcess> readerThread = new Thread<ExternalProcess>();
[88]43
44        protected PrintWriter input;
45        protected BufferedReader output;
46        protected Integer exitCode;
[101]47        protected String echoInput;
[107]48        protected String directory;
49        protected String host;
[88]50
[101]51        protected final EventListeners<ValueChange> listeners = new EventListeners<>();
[88]52
[90]53        @AutoAppendAnnotation
[101]54        @ParamAnnotation(id = "line_output")
55        public void addOutputListener(EventListener<ValueChange> listener) {
[88]56                synchronized (listeners) {
57                        listeners.add(listener);
58                }
59        }
60
[101]61        @ParamAnnotation(id = "line_output")
62        public void removeOutputListener(EventListener<ValueChange> listener) {
63                synchronized (listeners) {
64                        listeners.remove(listener);
65                }
66        }
67
[88]68        /**
69         *
70         */
71        public ExternalProcess() {
72                super();
73                setName("process");
74                arguments.add(null);
75        }
76
77        /**
78         * @return the command
79         */
[101]80        @ParamAnnotation(flags = ParamFlags.USERREADONLY)
[88]81        public String getCommand() {
82                return arguments.get(0);
83        }
84
85        /**
86         * @param command the command to set
87         */
88        @ParamAnnotation
89        public void setCommand(String command) {
90                arguments.set(0, command);
91        }
92
[90]93        protected void readerTask() {
[88]94
[101]95                log.debug("reading output from " + this);
[88]96                String line;
97                try {
98                        try {
99                                while ((line = output.readLine()) != null) {
[100]100                                        log.trace("read line: {}", line);
[88]101                                        synchronized (listeners) {
[101]102                                                listeners.actionForAll(new ValueChange(line));
[88]103                                        }
104                                }
105                        } catch (IOException e) {
106                                throw new FramsticksException().msg("failed to read line from output of process").cause(e);
107                        }
108                        try {
109                                exitCode = process.waitFor();
110                        } catch (InterruptedException e) {
111                                throw new FramsticksException().msg("failed to wait for process").cause(e);
112                        }
[102]113                        log.info("process ended {}", this);
[90]114                        // process = null;
[88]115                } catch (FramsticksException e) {
[100]116                        log.error("exception caught in process {}", this, e);
[88]117                }
[101]118                interruptJoinable();
[90]119                // finish();
[88]120        }
121
[101]122        @ParamAnnotation(flags = ParamFlags.USERREADONLY)
[88]123        public void setDirectory(String directory) {
[107]124                this.directory = directory;
[88]125        }
126
[107]127        /**
128         * @return the host
129         */
130        public String getHost() {
131                return host;
132        }
133
134        /**
135         * @param host the host to set
136         */
137        public void setHost(String host) {
138                this.host = host;
139        }
140
[88]141        @ParamAnnotation
142        public String getDirectory() {
[107]143                return Strings.toStringNullProof(directory, ".");
[88]144        }
145
146        @Override
[90]147        protected void joinableStart() {
[107]148
149                final ProcessBuilder builder = new ProcessBuilder();
150
151                builder.redirectErrorStream(true);
152                if (host == null) {
153                        setDirectory(System.getProperties().get("user.home") + "/" + getDirectory());
154                        setCommand(getDirectory() + "/" + getCommand());
155                        builder.directory(new File(getDirectory()));
156                } else {
157                        StringBuilder b = new StringBuilder();
158                        setCommand("./" + getCommand());
159                        for (String a : arguments) {
160                                b.append(" '").append(a).append("'");
161                        }
162                        arguments = Arrays.asList("ssh", host, "-tt", ("cd " + getDirectory() + " &&" + b.toString()));
163                }
[103]164                log.info("running process {}", this);
[107]165
[88]166                builder.command(arguments);
167                try {
168                        process = builder.start();
169                        input = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), Encoding.getDefaultCharset()));
170                        output = new BufferedReader(new InputStreamReader(process.getInputStream(), Encoding.getDefaultCharset()));
[90]171
[88]172                } catch (IOException e) {
173                        throw new FramsticksException().msg("failed to start process").cause(e);
174                }
175
[97]176                readerThread.dispatch(new RunAt<ExternalProcess>(ThrowExceptionHandler.getInstance()) {
[90]177
178                        @Override
[97]179                        protected void runAt() {
[90]180                                readerTask();
181                        }
182
183                });
184                Dispatching.use(readerThread, this);
[101]185
186                if (echoInput != null) {
187                        input.println(echoInput);
188                        input.flush();
189                }
[88]190        }
191
192        @Override
193        public String toString() {
[102]194                return getName() + arguments;
[88]195        }
196
197        /**
198         * @return the input
199         */
200        public PrintWriter getInput() {
201                return input;
202        }
203
[101]204        /**
205         * @return the echoInput
206         */
207        @ParamAnnotation(flags = ParamFlags.USERREADONLY)
208        public String getEchoInput() {
209                return echoInput;
210        }
211
212        /**
213         * @param echoInput the echoInput to set
214         */
215        @ParamAnnotation
216        public void setEchoInput(String echoInput) {
217                this.echoInput = echoInput;
218        }
219
[88]220        @Override
221        protected void joinableInterrupt() {
[90]222                process.destroy();
223                Dispatching.drop(readerThread, this);
224                // finish();
[88]225        }
226
[90]227        @Override
[101]228        @ParamAnnotation(flags = ParamFlags.USERREADONLY)
[90]229        public String getName() {
230                return readerThread.getName();
231        }
232
233        /**
234         * @param name the name to set
235         */
236        @ParamAnnotation
237        public void setName(String name) {
238                readerThread.setName(name);
239        }
240
241        @Override
242        protected void joinableFinish() {
243
244        }
245
246        @Override
247        protected void joinableJoin() throws InterruptedException {
248                Dispatching.join(readerThread);
249        }
250
251        @Override
252        public void childChangedState(Joinable joinable, JoinableState state) {
253                proceedToState(state);
254        }
255
256
257
[88]258}
Note: See TracBrowser for help on using the repository browser.