1 package org.apache.struts.scripting;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.InputStreamReader;
6 import java.io.Reader;
7 import java.nio.charset.StandardCharsets;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.nio.file.Paths;
11 import java.nio.file.attribute.FileTime;
12
13 import javax.script.Bindings;
14 import javax.script.Compilable;
15 import javax.script.CompiledScript;
16 import javax.script.ScriptContext;
17 import javax.script.ScriptEngine;
18 import javax.script.ScriptEngineManager;
19 import javax.script.ScriptException;
20
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import jakarta.servlet.ServletContext;
25
26
27
28
29
30
31
32
33
34
35 class Script {
36
37
38
39
40 private final Logger log =
41 LoggerFactory.getLogger(Script.class);
42
43
44 public final String name;
45
46
47
48
49
50 public final Path path;
51
52
53 public final ScriptEngine scriptEngine;
54
55
56 public final boolean compilable;
57
58
59 public FileTime lastModifiedTime;
60
61
62 public String content;
63
64
65 public CompiledScript compiledScript;
66
67
68 private IOException ioe;
69
70
71 private ScriptException se;
72
73
74
75
76
77
78
79
80
81
82
83 public Script(final ScriptEngineManager scriptEngineManager,
84 final ServletContext context, final String name) {
85
86 this.name = name;
87
88 final int i = name.lastIndexOf('.');
89 final String ext = i < 0 ? name : name.substring(i + 1);
90 scriptEngine = scriptEngineManager.getEngineByExtension(ext);
91 if (scriptEngine == null) {
92 se = new ScriptException("No ScriptEngine found for file: " + name);
93 }
94
95 compilable = scriptEngine instanceof Compilable;
96
97 final String realPath = context.getRealPath(name);
98 if (realPath == null) {
99 path = null;
100 } else {
101 path = Paths.get(realPath);
102 }
103
104 try (InputStream inputStream = realPath == null
105 ? context.getResourceAsStream(name)
106 : null) {
107
108 if (path == null && inputStream == null) {
109 se = new ScriptException("Could not find resource for file: " + name);
110 }
111
112 if (se != null) {
113 return;
114 }
115
116 try (Reader r = path == null
117 ? new InputStreamReader(inputStream, StandardCharsets.UTF_8)
118 : Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
119
120 lastModifiedTime = path != null
121 ? IOUtils.getLastModifiedTime(path)
122 : null;
123
124 log.debug("Loading new script: {}", name);
125
126 setContent(IOUtils.getStringFromReader(r));
127 }
128 } catch (IOException e) {
129 ioe = e;
130 }
131 }
132
133
134
135
136
137
138
139
140
141
142 public boolean checkNewContent() {
143 this.ioe = null;
144
145 if (path == null) {
146 return false;
147 }
148
149 try {
150 final FileTime lastModifiedTime = IOUtils.getLastModifiedTime(path);
151 if (this.lastModifiedTime != null &&
152 this.lastModifiedTime.compareTo(lastModifiedTime) >= 0) {
153
154 return false;
155 }
156
157 synchronized (this) {
158 log.debug("Loading updated script: {}", name);
159
160 this.lastModifiedTime = lastModifiedTime;
161
162 try (Reader r = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
163 setContent(IOUtils.getStringFromReader(r));
164 }
165 }
166 } catch (IOException e) {
167 ioe = e;
168 }
169
170 return true;
171 }
172
173
174
175
176
177
178
179
180 public Bindings getBindings() {
181 final Bindings bindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
182 bindings.clear();
183 bindings.put(ScriptEngine.FILENAME, name);
184
185 return bindings;
186 }
187
188
189
190
191
192
193
194
195 public void checkExceptions() throws ScriptException, IOException {
196 if (ioe != null) {
197 throw ioe;
198 }
199
200 if (se != null) {
201 throw se;
202 }
203 }
204
205
206
207
208
209
210
211
212 public Object eval() throws ScriptException {
213 if (compilable) {
214 if (compiledScript == null) {
215 throw se == null ? new ScriptException("Script could not compiled") : se;
216 }
217 return compiledScript.eval();
218 }
219
220 if (content == null || content.isEmpty()) {
221 throw se == null ? new ScriptException("Script could not compiled") : se;
222 }
223 return scriptEngine.eval(content);
224 }
225
226
227
228
229
230
231
232
233 private void setContent(final String content) {
234 this.se = null;
235 this.compiledScript = null;
236
237 if (content == null || content.isEmpty()) {
238 this.content = "";
239 } else if (compilable) {
240 this.content = null;
241
242 try {
243 this.compiledScript = ((Compilable) scriptEngine).compile(content);
244 } catch (ScriptException e) {
245 se = e;
246 }
247 } else {
248 this.content = content;
249 }
250 }
251 }