1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.scriptinterpreter;
20
21 import java.io.Closeable;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.PrintStream;
25 import java.nio.file.Files;
26 import java.util.HashMap;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Map;
31
32 import org.apache.commons.io.FilenameUtils;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36
37
38
39
40
41 public class ScriptRunner implements Closeable {
42
43 private static final Object LOCK = new Object();
44
45 private static final Logger LOG = LoggerFactory.getLogger(ScriptRunner.class);
46
47
48
49
50
51 private Map<String, ScriptInterpreter> scriptInterpreters;
52
53
54
55
56 private Map<String, Object> globalVariables;
57
58
59
60
61 private String encoding;
62
63
64
65
66 public ScriptRunner() {
67 scriptInterpreters = new LinkedHashMap<>();
68 scriptInterpreters.put("bsh", new BeanShellScriptInterpreter());
69 scriptInterpreters.put("groovy", new GroovyScriptInterpreter());
70 globalVariables = new HashMap<>();
71 }
72
73
74
75
76
77
78
79 public void addScriptInterpreter(String id, ScriptInterpreter scriptInterpreter) {
80 scriptInterpreters.put(id, scriptInterpreter);
81 }
82
83
84
85
86
87
88
89 public void setGlobalVariable(String name, Object value) {
90 this.globalVariables.put(name, value);
91 }
92
93
94
95
96
97
98
99
100
101 public void setClassPath(List<String> classPath) {
102 if (classPath != null && !classPath.isEmpty()) {
103 scriptInterpreters.values().forEach(scriptInterpreter -> scriptInterpreter.setClassPath(classPath));
104 }
105 }
106
107
108
109
110
111
112
113 public void setScriptEncoding(String encoding) {
114 this.encoding = encoding != null && !encoding.isEmpty() ? encoding : null;
115 }
116
117
118
119
120
121
122
123
124
125
126
127
128
129 public void run(
130 final String scriptDescription,
131 final File basedir,
132 final String relativeScriptPath,
133 final Map<String, ?> context,
134 final ExecutionLogger logger)
135 throws IOException, ScriptException {
136 if (relativeScriptPath == null) {
137 LOG.debug("{}: relativeScriptPath is null, not executing script", scriptDescription);
138 return;
139 }
140
141 final File scriptFile = resolveScript(new File(basedir, relativeScriptPath));
142
143 if (!scriptFile.exists()) {
144 LOG.debug(
145 "{} : no script '{}' found in directory {}",
146 scriptDescription,
147 relativeScriptPath,
148 basedir.getAbsolutePath());
149 return;
150 }
151
152 LOG.info(
153 "run {} {}.{}",
154 scriptDescription,
155 relativeScriptPath,
156 FilenameUtils.getExtension(scriptFile.getAbsolutePath()));
157
158 executeRun(scriptDescription, scriptFile, context, logger);
159 }
160
161
162
163
164
165
166
167
168
169
170
171 public void run(
172 final String scriptDescription, File scriptFile, final Map<String, ?> context, final ExecutionLogger logger)
173 throws IOException, ScriptException {
174
175 if (!scriptFile.exists()) {
176 LOG.debug("{} : script file not found in directory {}", scriptDescription, scriptFile.getAbsolutePath());
177 return;
178 }
179
180 LOG.info("run {} {}", scriptDescription, scriptFile.getAbsolutePath());
181
182 executeRun(scriptDescription, scriptFile, context, logger);
183 }
184
185 private void executeRun(
186 final String scriptDescription, File scriptFile, final Map<String, ?> context, final ExecutionLogger logger)
187 throws IOException, ScriptException {
188 ScriptInterpreter interpreter = getInterpreter(scriptFile);
189 if (LOG.isDebugEnabled()) {
190 String name = interpreter.getClass().getName();
191 name = name.substring(name.lastIndexOf('.') + 1);
192 LOG.debug("Running script with {} :{}", name, scriptFile);
193 }
194
195 String script;
196 try {
197 byte[] bytes = Files.readAllBytes(scriptFile.toPath());
198 if (encoding != null) {
199 script = new String(bytes, encoding);
200 } else {
201 script = new String(bytes);
202 }
203 } catch (IOException e) {
204 String errorMessage =
205 "error reading " + scriptDescription + " " + scriptFile.getPath() + ", " + e.getMessage();
206 throw new IOException(errorMessage, e);
207 }
208
209 Object result;
210 try {
211 if (logger != null) {
212 logger.consumeLine("Running " + scriptDescription + ": " + scriptFile);
213 }
214
215 PrintStream out = (logger != null) ? logger.getPrintStream() : null;
216
217 Map<String, Object> scriptVariables = new HashMap<>(this.globalVariables);
218 scriptVariables.put("basedir", scriptFile.getParentFile());
219 scriptVariables.put("context", context);
220
221 synchronized (LOCK) {
222 result = interpreter.evaluateScript(script, scriptVariables, out);
223 }
224 if (logger != null) {
225 logger.consumeLine("Finished " + scriptDescription + ": " + scriptFile);
226 }
227 } catch (ScriptEvaluationException e) {
228 Throwable t = (e.getCause() != null) ? e.getCause() : e;
229 if (logger != null) {
230 t.printStackTrace(logger.getPrintStream());
231 }
232 throw e;
233 }
234
235 if (!(result == null || Boolean.parseBoolean(String.valueOf(result)))) {
236 throw new ScriptReturnException("The " + scriptDescription + " returned " + result + ".", result);
237 }
238 }
239
240
241
242
243
244
245
246
247 private File resolveScript(File scriptFile) {
248 if (scriptFile != null && !scriptFile.exists()) {
249 for (String ext : this.scriptInterpreters.keySet()) {
250 File candidateFile = new File(scriptFile.getPath() + '.' + ext);
251 if (candidateFile.exists()) {
252 scriptFile = candidateFile;
253 break;
254 }
255 }
256 }
257 return scriptFile;
258 }
259
260
261
262
263
264
265
266
267
268 private ScriptInterpreter getInterpreter(File scriptFile) {
269 String ext = FilenameUtils.getExtension(scriptFile.getName()).toLowerCase(Locale.ENGLISH);
270 ScriptInterpreter interpreter = scriptInterpreters.get(ext);
271 if (interpreter == null) {
272 interpreter = scriptInterpreters.get("bsh");
273 }
274 return interpreter;
275 }
276
277
278
279
280
281
282 @Override
283 public void close() throws IOException {
284 for (ScriptInterpreter scriptInterpreter : scriptInterpreters.values()) {
285 scriptInterpreter.close();
286 }
287 scriptInterpreters.clear();
288 }
289 }