/* * PythonServerTemplate.java * * Brazil project web application toolkit, * export version: 2.3 * Copyright (c) 2000-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: suhler. * Portions created by suhler are Copyright (C) Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): drach, suhler. * * Version: 2.5 * Created by suhler on 00/09/08 * Last modified by suhler on 08/07/24 16:48:43 * * Version Histories: * * 2.5 08/07/24-16:48:43 (suhler) * preserve token accumulation state * * 2.4 04/11/30-15:19:40 (suhler) * fixed sccs version string * * 2.3 03/08/01-16:19:36 (suhler) * fixes for javadoc * * 2.2 03/07/07-14:45:11 (suhler) * Merged changes between child workspace "/home/suhler/brazil/naws" and * parent workspace "/net/mack.eng/export/ws/brazil/naws". * * 1.11.1.1 03/07/07-14:05:01 (suhler) * use addClosingTag() convenience method * * 2.1 02/10/01-16:38:53 (suhler) * version change * * 1.11 02/07/18-14:06:26 (suhler) * don't do \ * \XXX expansions with eval * * 1.10 01/07/16-16:50:52 (suhler) * use new Template convenience methods * * 1.6.1.1 01/06/04-11:06:58 (suhler) * jython -vs- jpython * * 1.9 01/05/24-17:07:55 (drach) * Add closing tag every time init() is called. * * 1.8 01/05/14-08:52:30 (drach) * Use new debug method in super class Template. * * 1.7 01/05/14-08:33:31 (drach) * Jython apparently doesn't have a classBasedException option. * * 1.6 01/04/06-08:51:29 (suhler) * added "eval" attribute to perform ${...} substitutions before running script * * 1.5 00/12/11-13:31:45 (suhler) * add class=props for automatic property extraction * * 1.4 00/10/06-16:04:19 (suhler) * fixed initialization bug, add python tracebacks when log=5 * * 1.3 00/09/13-14:48:41 (suhler) * move to python package, add tag * * 1.2 00/09/08-19:40:11 (suhler) * capture stdout of pyton interp * * 1.2 00/09/08-18:11:17 (Codemgr) * SunPro Code Manager data about conflicts, renames, etc... * Name history : 2 1 python/PythonServerTemplate.java * Name history : 1 0 tcl/PythonServerTemplate.java * * 1.1 00/09/08-18:11:16 (suhler) * date and time created 00/09/08 18:11:16 by suhler * */ package sunlabs.brazil.python; import sunlabs.brazil.server.Request; import sunlabs.brazil.server.Server; import sunlabs.brazil.handler.ResourceHandler; import sunlabs.brazil.template.RewriteContext; import sunlabs.brazil.template.Template; import sunlabs.brazil.util.Format; import org.python.core.PyException; import org.python.core.Options; import org.python.util.PythonInterpreter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Properties; /** * The PythonServerTemplate looks for each * <server language="python"> (or * <python>) * tag in an HTML page and treats the following data up to the next * </server> (or </python>) * tag as a python script to evaluate. *

* The reason that python 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> (or <python> and * </python> tags is replaced by all output written * to the Python standard output stream (if any). *

* All Python fragments within a given page are evaluated in the same Python * interpreter. The Python 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.

*
script *
The name of the Python script to evaluate when the interpreter is * created. This script only evaluated when the interp is created, * not on every request. The variables prefix and * server are set before this file is evaluated, and * are references to the parameters passed to a handler * init method. *
root *
The document root, if the script is a relative file name. * If the "root" property under the template prefix is not found, the * global "root" property is used. If the global "root" property is * not found, the current directory is used. *
debug *
If this configuration parameter is present, this class * replaces the <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 sets variables * in the Python interpreter, which can be used to interact back with Java to * do things like set the response headers:

*
request *
Exposes the {@link sunlabs.brazil.server.Request} Java object. * It is set anew at each request. *
prefix *
Exposes the handler prefix String. *
server *
Exposes the handler {@link sunlabs.brazil.server.Server} object. *
* If the attribute eval is present as an attribute, all * constructs off the form ${...} are substituted before processing the * script. * * @author Stephen Uhler * @version 2.5 */ public class PythonServerTemplate extends Template { private static final String SCRIPT = "script"; PythonInterpreter interp = null; ByteArrayOutputStream stdout; /* * Called at the beginning of each HTML document that this * PythonServerTemplate is asked to process. *

* 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

    *
  1. there was an error sourcing the initialization script. *
* If false is returned, an error message is logged. */ public boolean init(RewriteContext hr) { Properties props = hr.request.props; if (interp == null) { stdout = new ByteArrayOutputStream(); try { Options.classBasedExceptions = false; } catch (NoSuchFieldError e) {}; if (hr.server.logLevel >= Server.LOG_DIAGNOSTIC) { Options.showJavaExceptions = true; } interp = new PythonInterpreter(); String script = props.getProperty(hr.prefix + SCRIPT); // System.err.println("Creating Python interp"); try { interp.set("prefix", hr.prefix); interp.set("server", hr.server); if (script != null) { String body = ResourceHandler.getResourceString(props, hr.prefix, script); // System.err.println("startup: " + body); interp.exec(body); } } catch (IOException e) { hr.request.log(Server.LOG_ERROR, "reading init script", script); return false; } catch (PyException e) { hr.request.log(Server.LOG_ERROR, "initializing Python", e.toString()); return false; } // System.out.println("Init done"); } hr.addClosingTag("python"); try { hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix, "Setting request"); interp.set("request", hr.request); } catch (PyException e) { hr.request.log(Server.LOG_WARNING, hr.prefix, "Setting up Python request: " + e.toString()); done(hr); return false; } return super.init(hr); } /** * Processes the <server> tag. Substitues the * result of evaluating the following Python script into the resultant * HTML document. *

* Note: Currently, there is no mechanism for other language interpreters * to share the same server tag. * * @param hr * The request and associated HTML document that will be * processed. */ public void tag_server(RewriteContext hr) { if ("python".equals(hr.get("language")) == false) { return; } tag_python(hr); } /** * Processes the <python> tag. Substitues the * result of evaluating the following Python script into the resultant * HTML document. * * @param hr * The request and associated HTML document that will be * processed. */ public void tag_python(RewriteContext hr) { debug(hr); boolean eval = hr.isTrue("eval"); boolean was = hr.accumulate(false); hr.nextToken(); interp.setOut(stdout); String script = hr.getBody(); if (eval) { script = Format.subst(hr.request.props, script, true); } hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix, script); try { interp.exec(script); } catch (PyException e) { hr.append("\n\n"); hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix, e.toString()); } interp.setOut(System.out); hr.nextToken(); hr.append(stdout.toString()); stdout.reset(); hr.accumulate(was); } }