001: /*
002: * PythonServerTemplate.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 2000 Sun Microsystems, Inc.
007: *
008: * Sun Public License Notice
009: *
010: * The contents of this file are subject to the Sun Public License Version
011: * 1.0 (the "License"). You may not use this file except in compliance with
012: * the License. A copy of the License is included as the file "license.terms",
013: * and also available at http://www.sun.com/
014: *
015: * The Original Code is from:
016: * Brazil project web application Framework release 1.1.
017: * The Initial Developer of the Original Code is: suhler.
018: * Portions created by suhler are Copyright (C) Sun Microsystems, Inc.
019: * All Rights Reserved.
020: *
021: * Contributor(s): suhler.
022: *
023: * Version: 1.5
024: * Created by suhler on 00/09/08
025: * Last modified by suhler on 00/12/11 13:31:45
026: */
027:
028: package sunlabs.brazil.python;
029:
030: import sunlabs.brazil.server.Request;
031: import sunlabs.brazil.server.Server;
032: import sunlabs.brazil.handler.ResourceHandler;
033: import sunlabs.brazil.template.RewriteContext;
034: import sunlabs.brazil.template.Template;
035:
036: import org.python.core.PyException;
037: import org.python.core.Options;
038: import org.python.util.PythonInterpreter;
039:
040: import java.io.ByteArrayOutputStream;
041: import java.io.IOException;
042: import java.util.Properties;
043:
044: /**
045: * The <code>PythonServerTemplate</code> looks for each
046: * <code><server language="python"></code> (or
047: * <code><python></code>)
048: * tag in an HTML page and treats the following data up to the next
049: * <code></server></code> (or <code></python></code>)
050: * tag as a python script to evaluate.
051: * <p>
052: * The reason that python scripts are included in an HTML page is usually
053: * to generate dynamic, server-side content. After running this template,
054: * everything between and including the <code><server></code> and
055: * <code></server></code> (or <code><python></code> and
056: * <code></python></code> tags is replaced by all output written
057: * to the Python standard output stream (if any).
058: * <p>
059: * All Python fragments within a given page are evaluated in the same Python
060: * interpreter. The Python interpreter actually lives for the entire duration
061: * of this <code>Template</code> object, so the user can implement
062: * persistence across requests.
063: * <p>
064: * The following configuration parameters are used to initialize this
065: * template. <dl class=props>
066: * <dt> script
067: * <dd> The name of the Python script to evaluate when the interpreter is
068: * created. This script only evaluated when the interp is created,
069: * not on every request. The variables <code>prefix</code> and
070: * <code>server</code> are set before this file is evaluated, and
071: * are references to the parameters passed to a <code>handler</code>
072: * init method.
073: * <dt> root
074: * <dd> The document root, if the script is a relative file name.
075: * If the "root" property under the template prefix is not found, the
076: * global "root" property is used. If the global "root" property is
077: * not found, the current directory is used.
078: * <dt> debug
079: * <dd> If this configuration parameter is present, this class
080: * replaces the <code><server></code> and
081: * <code></server></code> tags with comments, so the user
082: * can keep track of where the dynamically generated content is coming
083: * from by examining the comments in the resultant HTML document.
084: * By default, the <code><server></code> and
085: * <code></server></code> are completely eliminated from the
086: * HTML document rather than changed into comments.
087: * </dl>
088: * <p>
089: * Before evaluating each HTML document, this class sets variables
090: * in the Python interpreter, which can be used to interact back with Java to
091: * do things like set the response headers: <dl>
092: * <dt> request
093: * <dd> Exposes the {@link sunlabs.brazil.server.Request} Java object.
094: * It is set anew at each request.
095: * <dt> prefix
096: * <dd> Exposes the handler prefix String.
097: * <dt> server
098: * <dd> Exposes the handler {@link sunlabs.brazil.server.Server} object.
099: * </dl>
100: *
101: * @author Stephen Uhler
102: * @version 1.5, 00/12/11
103: */
104:
105: public class PythonServerTemplate extends Template {
106: private static final String SCRIPT = "script";
107: private static final String DEBUG = "debug";
108:
109: PythonInterpreter interp = null;
110: ByteArrayOutputStream stdout;
111: transient boolean debug;
112:
113: /*
114: * Called at the beginning of each HTML document that this
115: * <code>PythonServerTemplate</code> is asked to process.
116: * <p>
117: * The first time this method is called, the initialization script is
118: * sourced into the interpreter, based on the configuration properties
119: * in the <code>Request</code>
120: *
121: * @param hr
122: * The request and associated HTML document that will be
123: * processed.
124: *
125: * @returns <code>true</code> interpreter was successfully initialized
126: * <code>false</code> otherwise. About the only way that the
127: * initialization could fail would be <ol>
128: * <li> there was an error sourcing the initialization script.
129: * </ol>
130: * If <code>false</code> is returned, an error message is logged.
131: */
132:
133: public boolean init(RewriteContext hr) {
134: Properties props = hr.request.props;
135:
136: if (interp == null) {
137: stdout = new ByteArrayOutputStream();
138: Options.classBasedExceptions = false;
139: if (hr.server.logLevel >= Server.LOG_DIAGNOSTIC) {
140: Options.showJavaExceptions = true;
141: }
142: interp = new PythonInterpreter();
143: hr.lex.getClosingTags().addElement("python");
144:
145: String script = props.getProperty(hr.prefix + SCRIPT);
146: // System.err.println("Creating Python interp");
147: try {
148: interp.set("prefix", hr.prefix);
149: interp.set("server", hr.server);
150:
151: if (script != null) {
152: String body = ResourceHandler.getResourceString(
153: props, hr.prefix, script);
154: // System.err.println("startup: " + body);
155: interp.exec(body);
156: }
157: } catch (IOException e) {
158: hr.request.log(Server.LOG_ERROR, "reading init script",
159: script);
160: return false;
161: } catch (PyException e) {
162: hr.request.log(Server.LOG_ERROR, "initializing Python",
163: e.toString());
164: return false;
165: }
166: // System.out.println("Init done");
167: }
168:
169: debug = (props.getProperty(hr.prefix + DEBUG) != null);
170:
171: try {
172: hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
173: "Setting request");
174: interp.set("request", hr.request);
175: } catch (PyException e) {
176: hr.request.log(Server.LOG_WARNING, hr.prefix,
177: "Setting up Python request: " + e.toString());
178: done(hr);
179: return false;
180: }
181: return true;
182: }
183:
184: /**
185: * Processes the <code><server></code> tag. Substitues the
186: * result of evaluating the following Python script into the resultant
187: * HTML document.
188: * <p>
189: * Note: Currently, there is no mechanism for other language interpreters
190: * to share the same <code>server</code> tag.
191: *
192: * @param hr
193: * The request and associated HTML document that will be
194: * processed.
195: */
196:
197: public void tag_server(RewriteContext hr) {
198: if ("python".equals(hr.get("language")) == false) {
199: return;
200: }
201: tag_python(hr);
202: }
203:
204: /**
205: * Processes the <code><python></code> tag. Substitues the
206: * result of evaluating the following Python script into the resultant
207: * HTML document.
208: *
209: * @param hr
210: * The request and associated HTML document that will be
211: * processed.
212: */
213:
214: public void tag_python(RewriteContext hr) {
215: if (debug) {
216: hr.append("<!-- " + hr.getBody() + " -->\n");
217: }
218: hr.accumulate(false);
219: hr.nextToken();
220: interp.setOut(stdout);
221: hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix, hr.getBody());
222: try {
223: interp.exec(hr.getBody());
224: } catch (PyException e) {
225: hr.append("\n<!-- server-side Python: error code "
226: + e.toString() + " -->\n");
227: hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix, e
228: .toString());
229: }
230: interp.setOut(System.out);
231: hr.nextToken();
232: hr.append(stdout.toString());
233: stdout.reset();
234: hr.accumulate(true);
235: }
236: }
|