|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
TemplateServlet.java | 0% | 0% | 0% | 0% |
|
1 |
/*
|
|
2 |
* $Id: TemplateServlet.java,v 1.8 2004/05/22 06:11:00 spullara Exp $
|
|
3 |
*
|
|
4 |
* Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
|
|
5 |
*
|
|
6 |
* Redistribution and use of this software and associated documentation
|
|
7 |
* ("Software"), with or without modification, are permitted provided that the
|
|
8 |
* following conditions are met:
|
|
9 |
*
|
|
10 |
* 1. Redistributions of source code must retain copyright statements and
|
|
11 |
* notices. Redistributions must also contain a copy of this document.
|
|
12 |
*
|
|
13 |
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
14 |
* this list of conditions and the following disclaimer in the documentation
|
|
15 |
* and/or other materials provided with the distribution.
|
|
16 |
*
|
|
17 |
* 3. The name "groovy" must not be used to endorse or promote products derived
|
|
18 |
* from this Software without prior written permission of The Codehaus. For
|
|
19 |
* written permission, please contact info@codehaus.org.
|
|
20 |
*
|
|
21 |
* 4. Products derived from this Software may not be called "groovy" nor may
|
|
22 |
* "groovy" appear in their names without prior written permission of The
|
|
23 |
* Codehaus. "groovy" is a registered trademark of The Codehaus.
|
|
24 |
*
|
|
25 |
* 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
|
|
26 |
*
|
|
27 |
* THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
|
|
28 |
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
29 |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
30 |
* DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
|
|
31 |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
32 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
33 |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
34 |
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
35 |
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
36 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
37 |
*
|
|
38 |
*/
|
|
39 |
package groovy.servlet;
|
|
40 |
|
|
41 |
import groovy.lang.Binding;
|
|
42 |
import groovy.text.SimpleTemplateEngine;
|
|
43 |
import groovy.text.Template;
|
|
44 |
import groovy.text.TemplateEngine;
|
|
45 |
|
|
46 |
import java.io.FileNotFoundException;
|
|
47 |
import java.io.IOException;
|
|
48 |
import java.net.URL;
|
|
49 |
import java.util.Enumeration;
|
|
50 |
import java.util.HashMap;
|
|
51 |
import java.util.Map;
|
|
52 |
|
|
53 |
import javax.servlet.ServletConfig;
|
|
54 |
import javax.servlet.ServletContext;
|
|
55 |
import javax.servlet.ServletException;
|
|
56 |
import javax.servlet.http.HttpServlet;
|
|
57 |
import javax.servlet.http.HttpServletRequest;
|
|
58 |
import javax.servlet.http.HttpServletResponse;
|
|
59 |
|
|
60 |
/**
|
|
61 |
* A generic servlet for templates.
|
|
62 |
*
|
|
63 |
* It wraps a <code>groovy.text.TemplateEngine</code> to process HTTP
|
|
64 |
* requests. By default, it uses the
|
|
65 |
* <code>groovy.text.SimpleTemplateEngine</code> which interprets JSP-like (or
|
|
66 |
* Canvas-like) templates. <br>
|
|
67 |
* <br>
|
|
68 |
*
|
|
69 |
* Example <code>HelloWorld.template</code>:
|
|
70 |
*
|
|
71 |
* <pre><code>
|
|
72 |
*
|
|
73 |
* <html>
|
|
74 |
* <body>
|
|
75 |
* <% 3.times { %>
|
|
76 |
* Hello World!
|
|
77 |
* <br>
|
|
78 |
*
|
|
79 |
* <% } %>
|
|
80 |
* </body>
|
|
81 |
* </html>
|
|
82 |
*
|
|
83 |
* </code></pre>
|
|
84 |
*
|
|
85 |
* <br>
|
|
86 |
* <br>
|
|
87 |
*
|
|
88 |
* Note: <br>
|
|
89 |
* Automatic binding of context variables and request (form) parameters is
|
|
90 |
* disabled by default. You can enable it by setting the servlet config init
|
|
91 |
* parameters to <code>true</code>.
|
|
92 |
*
|
|
93 |
* <pre><code>
|
|
94 |
* bindDefaultVariables = init("bindDefaultVariables", false);
|
|
95 |
* bindRequestParameters = init("bindRequestParameters", false);
|
|
96 |
* </code></pre>
|
|
97 |
*
|
|
98 |
* @author <a mailto:sormuras@web.de>Christian Stein </a>
|
|
99 |
* @version 1.3
|
|
100 |
*/
|
|
101 |
public class TemplateServlet extends HttpServlet { |
|
102 |
|
|
103 |
public static final String DEFAULT_CONTENT_TYPE = "text/html"; |
|
104 |
|
|
105 |
private ServletContext servletContext;
|
|
106 |
|
|
107 |
protected TemplateEngine templateEngine;
|
|
108 |
|
|
109 |
protected boolean bindDefaultVariables; |
|
110 |
|
|
111 |
protected boolean bindRequestParameters; |
|
112 |
|
|
113 |
/**
|
|
114 |
* Initializes the servlet.
|
|
115 |
*
|
|
116 |
* @param config
|
|
117 |
* Passed by the servlet container.
|
|
118 |
*/
|
|
119 | 0 |
public void init(ServletConfig config) { |
120 |
|
|
121 |
/*
|
|
122 |
* Save the context.
|
|
123 |
*/
|
|
124 | 0 |
this.servletContext = config.getServletContext();
|
125 |
|
|
126 |
/*
|
|
127 |
* BEGIN
|
|
128 |
*/
|
|
129 | 0 |
String className = getClass().getName(); |
130 | 0 |
servletContext.log("Initializing on " + className + "..."); |
131 |
|
|
132 |
/*
|
|
133 |
* Configure from servlet config.
|
|
134 |
*/
|
|
135 | 0 |
this.bindDefaultVariables = init(config, "bindDefaultVariables", false); |
136 | 0 |
this.bindRequestParameters = init(config, "bindRequestParameters", false); |
137 |
|
|
138 |
/*
|
|
139 |
* Get TemplateEngine instance.
|
|
140 |
*/
|
|
141 | 0 |
this.templateEngine = createTemplateEngine(config);
|
142 | 0 |
if (templateEngine == null) { throw new RuntimeException("Template engine not instantiated."); } |
143 |
|
|
144 |
/*
|
|
145 |
* END;
|
|
146 |
*/
|
|
147 | 0 |
String engineName = templateEngine.getClass().getName(); |
148 | 0 |
servletContext.log(className + " initialized on " + engineName + "."); |
149 |
} |
|
150 |
|
|
151 |
/**
|
|
152 |
* Convient evaluation of boolean configuration parameters.
|
|
153 |
*
|
|
154 |
* @return <code>true</code> or <code>false</code>.
|
|
155 |
* @param config
|
|
156 |
* Servlet configuration passed by the servlet container.
|
|
157 |
* @param param
|
|
158 |
* Name of the paramter to look up.
|
|
159 |
* @param value
|
|
160 |
* Default value if parameter name is not set.
|
|
161 |
*/
|
|
162 | 0 |
protected boolean init(ServletConfig config, String param, boolean value) { |
163 | 0 |
String string = config.getInitParameter(param); |
164 | 0 |
if (string == null) { return value; } |
165 | 0 |
return Boolean.valueOf(string).booleanValue();
|
166 |
} |
|
167 |
|
|
168 |
/**
|
|
169 |
* Creates the template engine.
|
|
170 |
*
|
|
171 |
* Called by {@link #init(ServletConfig)} and returns just <code>
|
|
172 |
* SimpleTemplateEngine()</code> if the init parameter <code>templateEngine</code>
|
|
173 |
* is not set.
|
|
174 |
*
|
|
175 |
* @return The underlying template engine.
|
|
176 |
* @param config
|
|
177 |
* This serlvet configuration passed by the container.
|
|
178 |
* @see #createTemplateEngine()
|
|
179 |
*/
|
|
180 | 0 |
protected TemplateEngine createTemplateEngine(ServletConfig config) {
|
181 | 0 |
String templateEngineClassName = config.getInitParameter("templateEngine");
|
182 | 0 |
if (templateEngineClassName == null) { |
183 | 0 |
return new SimpleTemplateEngine(); |
184 |
} |
|
185 | 0 |
try {
|
186 | 0 |
return (TemplateEngine) Class.forName(templateEngineClassName).newInstance();
|
187 |
} catch (InstantiationException e) {
|
|
188 | 0 |
servletContext.log("Could not instantiate template engine: " + templateEngineClassName, e);
|
189 |
} catch (IllegalAccessException e) {
|
|
190 | 0 |
servletContext.log("Could not access template engine class: " + templateEngineClassName, e);
|
191 |
} catch (ClassNotFoundException e) {
|
|
192 | 0 |
servletContext.log("Could not find template engine class: " + templateEngineClassName, e);
|
193 |
} |
|
194 | 0 |
return null; |
195 |
} |
|
196 |
|
|
197 |
/**
|
|
198 |
* Delegates to {@link #doRequest(HttpServletRequest, HttpServletResponse)}.
|
|
199 |
*/
|
|
200 | 0 |
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { |
201 | 0 |
doRequest(request, response); |
202 |
} |
|
203 |
|
|
204 |
/**
|
|
205 |
* Delegates to {@link #doRequest(HttpServletRequest, HttpServletResponse)}.
|
|
206 |
*/
|
|
207 | 0 |
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { |
208 | 0 |
doRequest(request, response); |
209 |
} |
|
210 |
|
|
211 |
/**
|
|
212 |
* Processes all requests by dispatching to helper methods.
|
|
213 |
*
|
|
214 |
* TODO Outline the algorithm. Although the method names are well-chosen. :)
|
|
215 |
*
|
|
216 |
* @param request
|
|
217 |
* The http request.
|
|
218 |
* @param response
|
|
219 |
* The http response.
|
|
220 |
* @throws ServletException
|
|
221 |
* ...
|
|
222 |
* @throws IOException
|
|
223 |
* ...
|
|
224 |
*/
|
|
225 | 0 |
protected void doRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException { |
226 |
|
|
227 | 0 |
Binding binding = null;
|
228 |
|
|
229 | 0 |
try {
|
230 |
|
|
231 |
/*
|
|
232 |
* Create binding.
|
|
233 |
*/
|
|
234 | 0 |
binding = createBinding(request, response); |
235 |
|
|
236 |
/*
|
|
237 |
* Set default content type.
|
|
238 |
*/
|
|
239 | 0 |
setContentType(request, response); |
240 |
|
|
241 |
/*
|
|
242 |
* Create the template by its engine.
|
|
243 |
*/
|
|
244 | 0 |
Template template = handleRequest(request, response, binding); |
245 |
|
|
246 |
/*
|
|
247 |
* Let the template, that is groovy, do the merge.
|
|
248 |
*/
|
|
249 | 0 |
merge(template, binding, response); |
250 |
|
|
251 |
} |
|
252 |
catch (Exception exception) {
|
|
253 |
|
|
254 |
/*
|
|
255 |
* Call exception handling hook.
|
|
256 |
*/
|
|
257 | 0 |
error(request, response, exception); |
258 |
|
|
259 |
} |
|
260 |
finally {
|
|
261 |
|
|
262 |
/*
|
|
263 |
* Indicate we are finally done with this request.
|
|
264 |
*/
|
|
265 | 0 |
requestDone(request, response, binding); |
266 |
|
|
267 |
} |
|
268 |
|
|
269 |
} |
|
270 |
|
|
271 |
/**
|
|
272 |
* Creates the application context.
|
|
273 |
*
|
|
274 |
* Sets 5 variables if and only if <code>bindDefaultParameters</code> is
|
|
275 |
* <code>true</code>:
|
|
276 |
*
|
|
277 |
* <pre><code>
|
|
278 |
* binding.setVariable("request", request);
|
|
279 |
* binding.setVariable("response", response);
|
|
280 |
* binding.setVariable("context", servletContext);
|
|
281 |
* binding.setVariable("session", request.getSession(true));
|
|
282 |
* binding.setVariable("out", response.getWriter());
|
|
283 |
* </code></pre>
|
|
284 |
*
|
|
285 |
* Binds all form parameters, too. This is, where we leave the clean MVC
|
|
286 |
* pattern and Velocity behind. (...) Nobody told you to quit Velocity
|
|
287 |
* anyway. :)
|
|
288 |
*
|
|
289 |
* @return Groovy Binding also known as application context.
|
|
290 |
* @param request
|
|
291 |
* The HTTP request.
|
|
292 |
* @param response
|
|
293 |
* The HTTP response.
|
|
294 |
* @throws Exception
|
|
295 |
* Any exception.
|
|
296 |
*/
|
|
297 | 0 |
protected Binding createBinding(HttpServletRequest request, HttpServletResponse response) throws Exception { |
298 |
|
|
299 |
/*
|
|
300 |
* Create empty binding.
|
|
301 |
*/
|
|
302 | 0 |
Binding binding = new Binding();
|
303 |
|
|
304 |
/*
|
|
305 |
* Bind default variables.
|
|
306 |
*/
|
|
307 | 0 |
if (bindDefaultVariables) {
|
308 | 0 |
binding.setVariable("request", request);
|
309 | 0 |
binding.setVariable("response", response);
|
310 | 0 |
binding.setVariable("context", servletContext);
|
311 | 0 |
binding.setVariable("session", request.getSession(true)); |
312 | 0 |
binding.setVariable("out", response.getWriter());
|
313 |
} |
|
314 |
|
|
315 |
/*
|
|
316 |
* Bind form (aka request) parameters.
|
|
317 |
*/
|
|
318 | 0 |
if (bindRequestParameters) {
|
319 | 0 |
Enumeration parameterNames = request.getParameterNames(); |
320 | 0 |
while (parameterNames.hasMoreElements()) {
|
321 | 0 |
String key = (String) parameterNames.nextElement(); |
322 | 0 |
if (binding.getVariables().containsKey(key)) {
|
323 | 0 |
servletContext.log("Key \"" + key + "\" already bound."); |
324 | 0 |
continue;
|
325 |
} |
|
326 | 0 |
String[] values = request.getParameterValues(key); |
327 | 0 |
if (values.length == 1) {
|
328 | 0 |
binding.setVariable(key, values[0]); |
329 |
} |
|
330 |
else {
|
|
331 | 0 |
binding.setVariable(key, values); |
332 |
} |
|
333 |
} |
|
334 |
} |
|
335 |
|
|
336 | 0 |
return binding;
|
337 |
|
|
338 |
} |
|
339 |
|
|
340 |
/**
|
|
341 |
* Sets {@link #DEFAULT_CONTENT_TYPE}.
|
|
342 |
*
|
|
343 |
* @param request
|
|
344 |
* The HTTP request.
|
|
345 |
* @param response
|
|
346 |
* The HTTP response.
|
|
347 |
*/
|
|
348 | 0 |
protected void setContentType(HttpServletRequest request, HttpServletResponse response) { |
349 |
|
|
350 | 0 |
response.setContentType(DEFAULT_CONTENT_TYPE); |
351 |
|
|
352 |
} |
|
353 |
|
|
354 |
/**
|
|
355 |
* Default request handling. <br>
|
|
356 |
*
|
|
357 |
* Leaving Velocity behind again. The template, actually the Groovy code in
|
|
358 |
* it, could handle/process the entire request. Good or not? This depends on
|
|
359 |
* you! :)<br>
|
|
360 |
*
|
|
361 |
* Anyway, here no exception is thrown -- but it's strongly recommended to
|
|
362 |
* override this method in derived class and do the real processing against
|
|
363 |
* the model inside it. The template should be used, like Velocity
|
|
364 |
* templates, to produce the view, the html page. Again, it's up to you!
|
|
365 |
*
|
|
366 |
* @return The template that will be merged.
|
|
367 |
* @param request
|
|
368 |
* The HTTP request.
|
|
369 |
* @param response
|
|
370 |
* The HTTP response.
|
|
371 |
* @param binding
|
|
372 |
* The application context.
|
|
373 |
* @throws Exception
|
|
374 |
*/
|
|
375 | 0 |
protected Template handleRequest(
|
376 |
HttpServletRequest request, |
|
377 |
HttpServletResponse response, |
|
378 |
Binding binding) |
|
379 |
throws Exception {
|
|
380 |
/*
|
|
381 |
* Delegate to getTemplate(String).
|
|
382 |
*/
|
|
383 | 0 |
return getTemplate(request);
|
384 |
} |
|
385 |
|
|
386 |
/**
|
|
387 |
* Gets the template by its name.
|
|
388 |
*
|
|
389 |
* @return The template that will be merged.
|
|
390 |
* @param templateName
|
|
391 |
* The name of the template.
|
|
392 |
* @throws Exception
|
|
393 |
* Any exception.
|
|
394 |
*/
|
|
395 | 0 |
protected Template getTemplate(HttpServletRequest request) throws Exception { |
396 |
|
|
397 |
/*
|
|
398 |
* If its an include we need to get the included path, not the main request path.
|
|
399 |
*/
|
|
400 | 0 |
String path = (String) request.getAttribute("javax.servlet.include.servlet_path");
|
401 | 0 |
if (path == null) { |
402 | 0 |
path = request.getServletPath(); |
403 |
} |
|
404 |
|
|
405 |
/*
|
|
406 |
* Delegate to resolveTemplateName(String). Twice if necessary.
|
|
407 |
*/
|
|
408 | 0 |
URL url = resolveTemplateName(path); |
409 | 0 |
if (url == null) { |
410 | 0 |
url = resolveTemplateName(request.getRequestURI()); |
411 |
} |
|
412 |
|
|
413 |
/*
|
|
414 |
* Template not found?
|
|
415 |
*/
|
|
416 | 0 |
if (url == null) { |
417 | 0 |
String uri = request.getRequestURI(); |
418 | 0 |
servletContext.log("Resource \"" + uri + "\" not found."); |
419 | 0 |
throw new FileNotFoundException(uri); |
420 |
} |
|
421 |
|
|
422 |
/*
|
|
423 |
* Delegate to getTemplate(URL).
|
|
424 |
*/
|
|
425 | 0 |
return getTemplate(url);
|
426 |
|
|
427 |
} |
|
428 |
|
|
429 |
/**
|
|
430 |
* Locate template and convert its location to an URL.
|
|
431 |
*
|
|
432 |
* @return The URL pointing to the resource... the template.
|
|
433 |
* @param templateName
|
|
434 |
* The name of the template.
|
|
435 |
* @throws Exception
|
|
436 |
* Any exception.
|
|
437 |
*/
|
|
438 | 0 |
protected URL resolveTemplateName(String templateName) throws Exception { |
439 |
|
|
440 |
/*
|
|
441 |
* Try servlet context resource facility.
|
|
442 |
*
|
|
443 |
* Good for names pointing to templates relatively to the servlet
|
|
444 |
* context.
|
|
445 |
*/
|
|
446 | 0 |
URL url = servletContext.getResource(templateName); |
447 | 0 |
if (url != null) { return url; } |
448 |
|
|
449 |
/*
|
|
450 |
* Precedence: Context classloader, Class classloader
|
|
451 |
* (those classloaders will delegate to the system classloader)
|
|
452 |
*/
|
|
453 | 0 |
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); |
454 | 0 |
url = classLoader.getResource(templateName); |
455 | 0 |
if (url != null) { return url; } |
456 |
|
|
457 |
/*
|
|
458 |
* Try the class loader, that loaded this class.
|
|
459 |
*
|
|
460 |
* Good for templates located within the class path.
|
|
461 |
*
|
|
462 |
*/
|
|
463 | 0 |
url = getClass().getResource(templateName); |
464 | 0 |
if (url != null) { return url; } |
465 |
|
|
466 |
/*
|
|
467 |
* Still, still here? Just return null.
|
|
468 |
*/
|
|
469 | 0 |
return null; |
470 |
|
|
471 |
} |
|
472 |
|
|
473 |
/**
|
|
474 |
* Gets the template by its url.
|
|
475 |
*
|
|
476 |
* @return The template that will be merged.
|
|
477 |
* @param templateURL
|
|
478 |
* The url of the template.
|
|
479 |
* @throws Exception
|
|
480 |
* Any exception.
|
|
481 |
*/
|
|
482 | 0 |
protected Template getTemplate(URL templateURL) throws Exception { |
483 |
|
|
484 |
/*
|
|
485 |
* Let the engine create the template from given URL.
|
|
486 |
*
|
|
487 |
* TODO Is createTemplate(Reader); faster? Fail safer?
|
|
488 |
*/
|
|
489 | 0 |
return templateEngine.createTemplate(templateURL);
|
490 |
|
|
491 |
} |
|
492 |
|
|
493 |
/**
|
|
494 |
* Merges the template and writes response.
|
|
495 |
*
|
|
496 |
* @param template
|
|
497 |
* The template that will be merged... now!
|
|
498 |
* @param binding
|
|
499 |
* The application context.
|
|
500 |
* @param response
|
|
501 |
* The HTTP response.
|
|
502 |
* @throws Exception
|
|
503 |
* Any exception.
|
|
504 |
*/
|
|
505 | 0 |
protected void merge(Template template, Binding binding, HttpServletResponse response) throws Exception { |
506 |
|
|
507 |
/*
|
|
508 |
* Set binding and write response.
|
|
509 |
*/
|
|
510 | 0 |
template.make(binding.getVariables()).writeTo(response.getWriter()); |
511 |
|
|
512 |
} |
|
513 |
|
|
514 |
/**
|
|
515 |
* Simply sends an internal server error page (code 500).
|
|
516 |
*
|
|
517 |
* @param request
|
|
518 |
* The HTTP request.
|
|
519 |
* @param response
|
|
520 |
* The HTTP response.
|
|
521 |
* @param exception
|
|
522 |
* The cause.
|
|
523 |
*/
|
|
524 | 0 |
protected void error(HttpServletRequest request, HttpServletResponse response, Exception exception) { |
525 |
|
|
526 | 0 |
try {
|
527 | 0 |
response.sendError(500, exception.getMessage()); |
528 |
} |
|
529 |
catch (IOException ioException) {
|
|
530 | 0 |
servletContext.log("Should not happen.", ioException);
|
531 |
} |
|
532 |
|
|
533 |
} |
|
534 |
|
|
535 |
/**
|
|
536 |
* Called one request is processed.
|
|
537 |
*
|
|
538 |
* This clean-up hook is always called, even if there was an exception
|
|
539 |
* flying around and the error method was executed.
|
|
540 |
*
|
|
541 |
* @param request
|
|
542 |
* The HTTP request.
|
|
543 |
* @param response
|
|
544 |
* The HTTP response.
|
|
545 |
* @param binding
|
|
546 |
* The application context.
|
|
547 |
*/
|
|
548 | 0 |
protected void requestDone(HttpServletRequest request, HttpServletResponse response, Binding binding) { |
549 |
|
|
550 |
/*
|
|
551 |
* Nothing to clean up.
|
|
552 |
*/
|
|
553 | 0 |
return;
|
554 |
|
|
555 |
} |
|
556 |
|
|
557 |
} |
|