1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.onehippo.forge.gallerymagick.core.command;
17
18 import java.io.ByteArrayOutputStream;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.OutputStream;
22 import java.io.UnsupportedEncodingException;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26
27 import org.apache.commons.exec.CommandLine;
28 import org.apache.commons.exec.DefaultExecuteResultHandler;
29 import org.apache.commons.exec.DefaultExecutor;
30 import org.apache.commons.exec.ExecuteException;
31 import org.apache.commons.exec.ExecuteStreamHandler;
32 import org.apache.commons.exec.ExecuteWatchdog;
33 import org.apache.commons.exec.PumpStreamHandler;
34 import org.apache.commons.io.IOUtils;
35 import org.apache.commons.lang.StringUtils;
36 import org.apache.commons.lang.math.NumberUtils;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
41
42
43 abstract public class AbstractMagickCommand {
44
45 private static final Logger log = LoggerFactory.getLogger(AbstractMagickCommand.class);
46
47
48
49
50 public static final String DEFAULT_SUBCOMMAND_CONVERT = "convert";
51
52
53
54
55 public static final String PROP_TIMEOUT = "org.onehippo.forge.gallerymagick.core.command.timeout";
56
57
58
59
60 private static final long DEFAULT_COMMAND_TIMEOUT = 3000L;
61
62
63
64
65 private File workingDirectory;
66
67
68
69
70 private final String executable;
71
72
73
74
75 private final String subCommand;
76
77
78
79
80 private List<String> arguments;
81
82
83
84
85
86
87 public AbstractMagickCommand(final String executable, final String subCommand) {
88 this.executable = executable;
89 this.subCommand = subCommand;
90 }
91
92
93
94
95
96 public File getWorkingDirectory() {
97 return workingDirectory;
98 }
99
100
101
102
103
104 public void setWorkingDirectory(File workingDirectory) {
105 this.workingDirectory = workingDirectory;
106 }
107
108
109
110
111
112 public String getExecutable() {
113 return executable;
114 }
115
116
117
118
119
120 public String getSubCommand() {
121 return subCommand;
122 }
123
124
125
126
127
128 public List<String> getArguments() {
129 if (arguments == null) {
130 return Collections.emptyList();
131 }
132
133 return Collections.unmodifiableList(arguments);
134 }
135
136
137
138
139
140 public void addArgument(final String argument) {
141 if (StringUtils.isBlank(argument)) {
142 throw new IllegalArgumentException("Blank argument.");
143 }
144
145 if (arguments == null) {
146 arguments = new ArrayList<>();
147 }
148
149 arguments.add(argument);
150 }
151
152
153
154
155 public void clearArguments() {
156 if (arguments != null) {
157 arguments.clear();
158 }
159 }
160
161
162
163
164
165
166 public void execute() throws IOException {
167 execute(null);
168 }
169
170
171
172
173
174
175
176 public void execute(final OutputStream stdOut) throws IOException {
177 CommandLine cmdLine = createCommandLine();
178 ByteArrayOutputStream errStream = null;
179 int exitValue = 0;
180 DefaultExecuteResultHandler resultHandler = null;
181
182 try {
183 errStream = new ByteArrayOutputStream(512);
184
185 final DefaultExecutor executor = new DefaultExecutor();
186 ExecuteStreamHandler streamHandler;
187
188 if (stdOut != null) {
189 streamHandler = new PumpStreamHandler(stdOut, errStream);
190 } else {
191 streamHandler = new PumpStreamHandler(System.out, errStream);
192 }
193
194 executor.setStreamHandler(streamHandler);
195
196 if (getWorkingDirectory() != null) {
197 executor.setWorkingDirectory(getWorkingDirectory());
198 }
199
200 long timeout = NumberUtils.toLong(System.getProperty(PROP_TIMEOUT), DEFAULT_COMMAND_TIMEOUT);
201
202 if (timeout > 0) {
203 ExecuteWatchdog watchdog = new ExecuteWatchdog(DEFAULT_COMMAND_TIMEOUT);
204 executor.setWatchdog(watchdog);
205 resultHandler = new DefaultExecuteResultHandler();
206 executor.execute(cmdLine, resultHandler);
207 log.debug("Executed with watchdog: {}", cmdLine);
208 resultHandler.waitFor();
209 } else {
210 exitValue = executor.execute(cmdLine);
211 log.debug("Executed without watchdog: {}", cmdLine);
212 }
213 } catch (ExecuteException | InterruptedException e) {
214 if (resultHandler != null) {
215 exitValue = resultHandler.getExitValue();
216 }
217 if (e.getCause() == null) {
218 throw new MagickExecuteException(getExecutionErrorMessage(cmdLine, errStream, e), exitValue);
219 } else {
220 throw new MagickExecuteException(getExecutionErrorMessage(cmdLine, errStream, e), exitValue, e.getCause());
221 }
222 } finally {
223 IOUtils.closeQuietly(errStream);
224 }
225 }
226
227 private String getExecutionErrorMessage(final CommandLine cmdLine, final ByteArrayOutputStream errStream,
228 final Exception e) throws UnsupportedEncodingException {
229 StringBuilder sbMsg = new StringBuilder(256);
230 sbMsg.append(StringUtils.trim(errStream.toString("UTF-8")));
231 sbMsg.append(' ').append(cmdLine.toString());
232 sbMsg.append(". ").append(e.getMessage());
233 return sbMsg.toString();
234 }
235
236
237
238
239
240 abstract protected CommandLine createCommandLine();
241
242 }