1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.springframework.extensions.webscripts;
20
21 import java.io.IOException;
22 import java.util.Collections;
23 import java.util.Date;
24 import java.util.HashMap;
25 import java.util.Map;
26
27 import javax.servlet.http.HttpServletResponse;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.springframework.extensions.webscripts.Description.RequiredAuthentication;
32
33
34
35
36
37
38
39
40
41
42
43
44 public abstract class AbstractRuntime implements Runtime
45 {
46
47 protected static final Log logger = LogFactory.getLog(AbstractRuntime.class);
48
49
50 protected RuntimeContainer container;
51
52
53
54
55
56
57 public AbstractRuntime(RuntimeContainer container)
58 {
59 this.container = container;
60 }
61
62
63
64
65 public Container getContainer()
66 {
67 return container;
68 }
69
70
71
72
73 final public void executeScript()
74 {
75 long startRuntime = System.nanoTime();
76
77 String method = getScriptMethod();
78 String scriptUrl = null;
79 Match match = null;
80
81 try
82 {
83
84 scriptUrl = getScriptUrl();
85 if (scriptUrl == null || scriptUrl.length() == 0)
86 {
87 throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Script URL not specified");
88 }
89
90 if (logger.isDebugEnabled())
91 logger.debug("(Runtime=" + getName() + ", Container=" + container.getName() + ") Processing script url (" + method + ") " + scriptUrl);
92
93 WebScriptRequest scriptReq = null;
94 WebScriptResponse scriptRes = null;
95 Authenticator auth = null;
96
97 RequiredAuthentication containerRequiredAuth = container.getRequiredAuthentication();
98
99 if (! containerRequiredAuth.equals(RequiredAuthentication.none))
100 {
101
102 scriptReq = createRequest(null);
103 scriptRes = createResponse();
104 auth = createAuthenticator();
105
106 if (logger.isDebugEnabled())
107 logger.debug("(Runtime=" + getName() + ", Container=" + container.getName() + ") Container requires pre-auth: "+containerRequiredAuth);
108
109 boolean preAuth = true;
110
111 if (auth.emptyCredentials())
112 {
113
114 match = container.getRegistry().findWebScript(method, scriptUrl);
115 if ((match != null) && (match.getWebScript().getDescription().getRequiredAuthentication().equals(RequiredAuthentication.none)))
116 {
117 preAuth = false;
118 }
119 }
120
121 if (preAuth && (! container.authenticate(auth, containerRequiredAuth)))
122 {
123 return;
124 }
125 }
126
127 if (match == null)
128 {
129 match = container.getRegistry().findWebScript(method, scriptUrl);
130 }
131
132 match = container.getRegistry().findWebScript(method, scriptUrl);
133 if (match == null || match.getKind() == Match.Kind.URI)
134 {
135 if (match == null)
136 {
137 String msg = "Script url " + scriptUrl + " does not map to a Web Script.";
138 if (logger.isDebugEnabled())
139 logger.debug(msg);
140 throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, msg);
141 }
142 else
143 {
144 String msg = "Script url " + scriptUrl + " does not support the method " + method;
145 if (logger.isDebugEnabled())
146 logger.debug(msg);
147 throw new WebScriptException(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
148 }
149 }
150
151
152 scriptReq = createRequest(match);
153 scriptRes = createResponse();
154
155 if (auth == null)
156 {
157
158 auth = createAuthenticator();
159 }
160
161 if (logger.isDebugEnabled())
162 logger.debug("Agent: " + scriptReq.getAgent());
163
164 long startScript = System.nanoTime();
165 final WebScript script = match.getWebScript();
166 final Description description = script.getDescription();
167
168 try
169 {
170 if (logger.isDebugEnabled())
171 {
172 String reqFormat = scriptReq.getFormat();
173 String format = (reqFormat == null || reqFormat.length() == 0) ? "[undefined]" : reqFormat;
174 Description desc = scriptReq.getServiceMatch().getWebScript().getDescription();
175 logger.debug("Invoking Web Script " + description.getId() + " (format " + format + ", style: " + desc.getFormatStyle() + ", default: " + desc.getDefaultFormat() + ")");
176 }
177
178 executeScript(scriptReq, scriptRes, auth);
179 }
180 finally
181 {
182 if (logger.isDebugEnabled())
183 {
184 long endScript = System.nanoTime();
185 logger.debug("Web Script " + description.getId() + " executed in " + (endScript - startScript)/1000000f + "ms");
186 }
187 }
188 }
189 catch(Throwable e)
190 {
191
192 if (logger.isErrorEnabled())
193 {
194 logger.error("Exception from executeScript - redirecting to status template error: " + e.getMessage(), e);
195 }
196
197
198 WebScriptRequest req = createRequest(null);
199 WebScriptResponse res = createResponse();
200
201
202 int statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
203 StatusTemplate statusTemplate = null;
204 Map<String, Object> statusModel = null;
205 if (e instanceof WebScriptException)
206 {
207 WebScriptException we = (WebScriptException)e;
208 statusCode = we.getStatus();
209 statusTemplate = we.getStatusTemplate();
210 statusModel = we.getStatusModel();
211 }
212
213
214 if (statusTemplate == null)
215 {
216
217
218
219
220 statusTemplate = getStatusCodeTemplate(statusCode);
221
222 String validTemplatePath = container.getTemplateProcessorRegistry().findValidTemplatePath(statusTemplate.getPath());
223 if (validTemplatePath == null)
224 {
225 statusTemplate = getStatusTemplate();
226
227 validTemplatePath = container.getTemplateProcessorRegistry().findValidTemplatePath(statusTemplate.getPath());
228 if (validTemplatePath == null)
229 {
230 throw new WebScriptException("Failed to find status template " + statusTemplate.getPath() + " (format: " + statusTemplate.getFormat() + ")");
231 }
232 }
233 }
234
235
236 if (statusModel == null || statusModel.equals(Collections.EMPTY_MAP))
237 {
238 statusModel = new HashMap<String, Object>(8, 1.0f);
239 statusModel.put("url", new URLModel(req));
240 statusModel.put("server", container.getDescription());
241 statusModel.put("date", new Date());
242 if (match != null && match.getWebScript() != null)
243 {
244 statusModel.put("webscript", match.getWebScript().getDescription());
245 }
246 }
247
248
249 Status status = new Status();
250 status.setCode(statusCode);
251 status.setMessage(e.getMessage() != null ? e.getMessage() : e.toString());
252 status.setException(e);
253 statusModel.put("status", status);
254
255
256 String mimetype = container.getFormatRegistry().getMimeType(req.getAgent(), statusTemplate.getFormat());
257 if (mimetype == null)
258 {
259 throw new WebScriptException("Web Script format '" + statusTemplate.getFormat() + "' is not registered");
260 }
261
262 if (logger.isDebugEnabled())
263 {
264 logger.debug("Force success status header in response: " + req.forceSuccessStatus());
265 logger.debug("Sending status " + statusCode + " (Template: " + statusTemplate.getPath() + ")");
266 logger.debug("Rendering response: content type=" + mimetype);
267 }
268
269 res.reset();
270 Cache cache = new Cache();
271 cache.setNeverCache(true);
272 res.setCache(cache);
273 res.setStatus(req.forceSuccessStatus() ? HttpServletResponse.SC_OK : statusCode);
274 res.setContentType(Format.HTML.mimetype() + ";charset=UTF-8");
275 try
276 {
277 String validTemplatePath = container.getTemplateProcessorRegistry().findValidTemplatePath(statusTemplate.getPath());
278 TemplateProcessor statusProcessor = container.getTemplateProcessorRegistry().getTemplateProcessor(validTemplatePath);
279 statusProcessor.process(validTemplatePath, statusModel, res.getWriter());
280 }
281 catch (Exception e1)
282 {
283 logger.error("Internal error", e1);
284 throw new WebScriptException("Internal error", e1);
285 }
286 }
287 finally
288 {
289 long endRuntime = System.nanoTime();
290 if (logger.isDebugEnabled())
291 logger.debug("Processed script url (" + method + ") " + scriptUrl + " in " + (endRuntime - startRuntime)/1000000f + "ms");
292 }
293 }
294
295
296
297
298
299
300
301
302
303
304 protected void executeScript(WebScriptRequest scriptReq, WebScriptResponse scriptRes, Authenticator auth)
305 throws IOException
306 {
307 container.executeScript(scriptReq, scriptRes, auth);
308 }
309
310
311
312
313
314
315
316 protected StatusTemplate getStatusCodeTemplate(int statusCode)
317 {
318 return new StatusTemplate("/" + statusCode + ".ftl", WebScriptResponse.HTML_FORMAT);
319 }
320
321
322
323
324
325
326 protected StatusTemplate getStatusTemplate()
327 {
328 return new StatusTemplate("/status.ftl", WebScriptResponse.HTML_FORMAT);
329 }
330
331
332
333
334 public Map<String, Object> getScriptParameters()
335 {
336 return Collections.emptyMap();
337 }
338
339
340
341
342 public Map<String, Object> getTemplateParameters()
343 {
344 return Collections.emptyMap();
345 }
346
347
348
349
350
351
352 protected abstract String getScriptMethod();
353
354
355
356
357
358
359 protected abstract String getScriptUrl();
360
361
362
363
364
365
366
367 protected abstract WebScriptRequest createRequest(Match match);
368
369
370
371
372
373
374 protected abstract WebScriptResponse createResponse();
375
376
377
378
379
380
381 protected abstract Authenticator createAuthenticator();
382
383
384
385
386
387
388
389
390 protected static WebScriptRequest getRealWebScriptRequest(WebScriptRequest request)
391 {
392 WebScriptRequest real = request;
393 while(real instanceof WrappingWebScriptRequest)
394 {
395 real = ((WrappingWebScriptRequest)real).getNext();
396 }
397 return real;
398 }
399
400
401
402
403
404
405
406 protected static WebScriptResponse getRealWebScriptResponse(WebScriptResponse response)
407 {
408 WebScriptResponse real = response;
409 while(real instanceof WrappingWebScriptResponse)
410 {
411 real = ((WrappingWebScriptResponse)real).getNext();
412 }
413 return real;
414 }
415
416 }