/*
* TclServerTemplate.java
*
* Brazil project web application toolkit,
* export version: 2.3
* Copyright (c) 1999-2008 Sun Microsystems, Inc.
*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is included as the file "license.terms",
* and also available at http://www.sun.com/
*
* The Original Code is from:
* Brazil project web application toolkit release 2.3.
* The Initial Developer of the Original Code is: cstevens.
* Portions created by cstevens are Copyright (C) Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): cstevens, suhler.
*
* Version: 2.5
* Created by cstevens on 99/10/19
* Last modified by suhler on 08/07/24 16:48:22
*
* Version Histories:
*
* 2.5 08/07/24-16:48:22 (suhler)
* preserve token accumulation state
*
* 2.4 04/11/30-15:11:27 (suhler)
* fixed sccs version string
*
* 2.3 03/08/01-16:19:31 (suhler)
* fixes for javadoc
*
* 2.2 03/07/07-14:45:22 (suhler)
* Merged changes between child workspace "/home/suhler/brazil/naws" and
* parent workspace "/net/mack.eng/export/ws/brazil/naws".
*
* 1.20.1.1 03/07/07-14:08:50 (suhler)
* use addClosingTag() convenience method
*
* 2.1 02/10/01-16:37:25 (suhler)
* version change
*
* 1.20 01/08/14-16:40:10 (suhler)
* add "eval" option for consistency with python
*
* 1.19 01/03/12-17:42:35 (cstevens)
* Merged changes between child workspace "/home/cstevens/ws/brazil/naws" and
* parent workspace "/export/ws/brazil/naws".
*
* 1.18 01/03/06-09:10:40 (suhler)
* move interp creation to first use, to avoid redundant interp creation.
* Allow TclServerTemplate
looks for each
* <server language="tcl">
* (or <"tcl">
)
* tag in an HTML page and treats the following data up to the next
* </server>
tag as a Tcl script to evaluate.
* If the optional attribute eval
is present,
* the all ${...} constructs are replaced using
* {@link sunlabs.brazil.util.Format#subst}
* before being passed to the Tcl interpreter.
*
* The reason that Tcl scripts are included in an HTML page is usually
* to generate dynamic, server-side content. After running this template,
* everything between and including the <server>
and
* </server>
tags is replaced with the result of
* evaluating the Tcl script as follows:
puts "hello"
).
* return "bob"
).
* puts
and a final return
can both be
* used within a single Tcl fragment.
*
* All Tcl fragments within a given page are evaluated in the same Tcl
* interpreter. The Tcl interpreter actually lives for the entire duration
* of this Template
object, so the user can implement
* persistence across requests.
*
* The following configuration parameters are used to initialize this * template.
prefix
and
* server
are set before this file is evaluated, and
* are references to the parameters passed to a handler
* init method.
* <server>
and
* </server>
tags with comments, so the user
* can keep track of where the dynamically generated content is coming
* from by examining the comments in the resultant HTML document.
* By default, the <server>
and
* </server>
are completely eliminated from the
* HTML document rather than changed into comments.
* * Before evaluating each HTML document, this class variables * in the Tcl interpreter, which can be used to interact back with Java to * do things like set the response headers:
TclServerTemplate
is asked to process.
*
* Redirects the standard output of the Tcl interpreter to the
* resultant HTML document and exposes the Request
* object as a Tcl variable.
*
* The first time this method is called, the initialization script is
* sourced into the interpreter, based on the configuration properties
* in the Request
*
* @param hr
* The request and associated HTML document that will be
* processed.
*
* @return true
interpreter was successfully initialized
* false
otherwise. About the only way that the
* initialization could fail would be
request
* or server
as array variables.
* false
is returned, an error message is logged.
*/
public boolean
setup(RewriteContext hr) {
Properties props = hr.request.props;
if (interp == null) {
interp = new Interp();
String script = props.getProperty(hr.prefix + SCRIPT);
String session = (hr.sessionId == null) ? "none" : hr.sessionId;
try {
interp.eval("package require java");
interp.eval("set prefix " + hr.prefix);
interp.eval("set SessionId " + session);
TclObject server = ReflectObject.newInstance(interp,
Server.class, hr.server);
TclUtil.setVar(interp, "server", server, 0);
if (script != null) {
String body = ResourceHandler.getResourceString(props,
hr.prefix, script);
interp.eval(body);
}
} catch (IOException e) {
hr.request.log(Server.LOG_ERROR, "reading init script", script);
return false;
} catch (TclException e) {
e.printStackTrace();
if (e.getCompletionCode() != TCL.RETURN) {
hr.request.log(Server.LOG_ERROR, "loading java package",
e.toString());
return false;
}
}
}
debug = (props.getProperty(hr.prefix + DEBUG) != null);
try {
chan = new TclTemplateChannel(interp, hr);
request = ReflectObject.newInstance(interp, Request.class,
hr.request);
interp.eval("set request " + request);
} catch (TclException e) {
hr.request.log(Server.LOG_WARNING, hr.prefix,
"Setting up TCL environ: " + e.toString());
done(hr);
return false;
}
return true;
}
/**
* Called after the HTML document has been processed.
*
* Releases the resources allocated by init
. This method
* should be called to ensure that the HtmlRewriter
and
* all its attendant data structures are not preserved indefinitely
* (until the next request).
*
* @param hr
* The request and associated HTML document that was processed.
*
* @return true
always, indicating that this document was
* successfully processed to completion.
*/
public boolean
done(RewriteContext hr)
{
if (chan != null) {
chan.unregister();
}
if (request != null) {
request.release();
}
chan=null;
request=null;
return true;
}
/**
* Processes the <server>
tag. Substitues the
* result of evaluating the following Tcl script into the resultant
* HTML document.
*
* Note: Currently, there is no mechanism for other language interpreters
* to share the same server
tag. Use the
* <tcl>
tag instead.
*
* @param hr
* The request and associated HTML document that will be
* processed.
*/
public void
tag_server(RewriteContext hr) {
String server = hr.getBody();
if ("tcl".equals(hr.get("language")) == false) {
return;
}
tag_tcl(hr);
}
/**
* Processes the <tcl>
tag. Substitues the
* result of evaluating the following Tcl script into the resultant
* HTML document.
*
* @param hr
* The request and associated HTML document that will be
* processed.
*/
public void
tag_tcl(RewriteContext hr) {
debug(hr);
boolean eval = hr.isTrue("eval");
if (newPage) {
newPage=false;
setup(hr);
}
boolean was = hr.accumulate(false);
hr.nextToken();
String script = hr.getBody();
if (eval) {
script = Format.subst(hr.request.props, script,true);
}
try {
interp.eval(script);
} catch (TclException e) {
if (e.getCompletionCode() == TCL.RETURN) {
String result = interp.getResult().toString();
if (result.length() > 0) {
hr.append(result);
}
} else {
hr.append("\n\n");
if (debug) {
TclObject errorInfo;
try {
errorInfo = interp.getVar("errorInfo", null,
TCL.GLOBAL_ONLY);
} catch (Exception e2) {
errorInfo = null;
}
hr.append("\n\n");
}
}
}
hr.nextToken();
if (debug) {
hr.append("");
}
hr.accumulate(was);
}
}