001: /*
002: * TclFilter.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 1999-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): cstevens, suhler.
022: *
023: * Version: 1.12
024: * Created by suhler on 99/08/06
025: * Last modified by suhler on 00/12/11 13:33:18
026: */
027:
028: package sunlabs.brazil.tcl;
029:
030: import sunlabs.brazil.filter.Filter;
031: import sunlabs.brazil.server.FileHandler;
032: import sunlabs.brazil.server.Request;
033: import sunlabs.brazil.server.Server;
034: import sunlabs.brazil.session.SessionManager;
035: import sunlabs.brazil.util.http.MimeHeaders;
036:
037: import tcl.lang.Interp;
038: import tcl.lang.ReflectObject;
039: import tcl.lang.TCL;
040: import tcl.lang.TclException;
041: import tcl.lang.TclObject;
042: import tcl.lang.TclUtil;
043:
044: import java.io.File;
045:
046: /**
047: * Filter for writing Filters in tcl
048: * Run a tcl startup script when the handler is initialized.
049: * anytime a request is made, call the <b>respond</b> callback
050: * in the tcl code, which is provided with the
051: * {@link sunlabs.brazil.server.Request} object as an argument.
052: * <p>
053: * This provides a bare-bones tcl interface. The startup script
054: * should provide a friendlier interface.
055: * <p>
056: * This handler requires that <code>tcljava.jar</code> and <code>jacl.jar</code>
057: * jar files (both available
058: * <a href="http://www.scriptics.com/software/java1.0.html">)here</a>.
059: * If you need Tcl's regular expressions, you will also need
060: * <code>oro.jar</code>, available at the location above.
061: * <p>
062: * The following server properties are used:
063: * <dl class=props>
064: * <dt>script <dd> The name of the TCL file sourced on startup.
065: * The {@link #init} parameters are made available as the global
066: * variables <code>prefix</code> and <code>server</code>.
067: * </dl>
068: *
069: * @author Stephen Uhler
070: * @version %V% TclHandler.java
071: */
072:
073: public class TclFilter implements Filter {
074: Server server;
075: String propsPrefix;
076: String scriptName;
077:
078: static final String SCRIPT = "script";
079:
080: /**
081: * extract the filter properties.
082: */
083:
084: public boolean init(Server server, String prefix) {
085: this .server = server;
086: propsPrefix = prefix;
087: // System.out.println("initing (" + prefix + ")");
088: scriptName = server.props.getProperty(prefix + SCRIPT, prefix
089: + "tcl");
090: File scriptFile = new File(scriptName);
091: if (!scriptFile.isAbsolute()) {
092: scriptFile = new File(server.props.getProperty(
093: FileHandler.ROOT, "."), scriptName);
094: }
095: scriptName = scriptFile.getAbsolutePath();
096: server.log(Server.LOG_DIAGNOSTIC, prefix, "Using: "
097: + scriptName);
098: return true;
099: }
100:
101: /**
102: * We don't need to look at the request.
103: */
104:
105: public boolean respond(Request request) {
106: return false;
107: }
108:
109: /**
110: * For now, only filter text/html. This restriction will be
111: * lifted once I figure out how
112: */
113:
114: public boolean shouldFilter(Request request, MimeHeaders headers) {
115: String type = headers.get("content-type");
116: return (type != null && type.startsWith("text/html"));
117: }
118:
119: /*
120: * Find (or create) the interpreter.
121: * Call the tcl callback script.
122: * The <code>request</code> object reference is appended to the
123: * <code>callback</code> parameter.
124: * @return true, if the callback script returns "true" or "1".
125: */
126:
127: public byte[] filter(Request request, MimeHeaders headers,
128: byte[] content) {
129:
130: /*
131: * Find the proper interp, creating it if needed. If newly created
132: * (or if no SessionID variable was found) - initialize the interp
133: */
134:
135: String sessionId = request.props.getProperty("SessionID",
136: "common");
137: request.log(Server.LOG_DIAGNOSTIC, " Using session: "
138: + sessionId);
139: Interp interp = (Interp) SessionManager.getSession(sessionId,
140: propsPrefix + "TCL", Interp.class);
141:
142: int code = 0;
143: synchronized (interp) {
144: setupInterp(interp, sessionId);
145: try {
146: // System.out.println("running eval");
147: TclUtil.setVar(interp, "content", new String(content),
148: TCL.GLOBAL_ONLY);
149: interp.eval("filter"
150: + " "
151: + ReflectObject.newInstance(interp,
152: Request.class, request)
153: + " "
154: + ReflectObject.newInstance(interp,
155: MimeHeaders.class, headers));
156: TclObject res = interp.getVar("content",
157: TCL.GLOBAL_ONLY);
158: content = res.toString().getBytes();
159: } catch (TclException e) {
160: code = e.getCompletionCode();
161: String trace = e.toString();
162: // System.out.println("Tcl Oops: " + code + " " + e);
163: if (code == 1) {
164: try {
165: trace = interp.getVar("errorInfo",
166: TCL.GLOBAL_ONLY).toString();
167: } catch (Exception e1) {
168: }
169: }
170: request.log(Server.LOG_WARNING, propsPrefix + trace);
171: }
172: } // end sync block
173: return content;
174: }
175:
176: /**
177: * Setup a tcl interpreter for this session
178: */
179:
180: private void setupInterp(Interp interp, String id) {
181: try {
182: interp.getVar("SessionID", TCL.GLOBAL_ONLY);
183: return;
184: } catch (TclException e) {
185: // System.out.println("Creating new TCL interp");
186: }
187: try {
188: TclUtil.setVar(interp, "tcl_interactive", "0",
189: TCL.GLOBAL_ONLY);
190: TclUtil
191: .setVar(interp, "argv0", scriptName,
192: TCL.GLOBAL_ONLY);
193: TclUtil.setVar(interp, "prefix", propsPrefix,
194: TCL.GLOBAL_ONLY);
195: TclUtil.setVar(interp, "SessionID", id, TCL.GLOBAL_ONLY);
196: TclUtil.setVar(interp, "server", ReflectObject.newInstance(
197: interp, Server.class, server), TCL.GLOBAL_ONLY);
198: // System.out.println("About to run: " + scriptName);
199: interp.evalFile(scriptName);
200: // System.out.println("DONE");
201: } catch (TclException e) {
202: int code = e.getCompletionCode();
203: String trace = e.toString();
204: if (code == 1) {
205: try {
206: trace = interp.getVar("errorInfo", TCL.GLOBAL_ONLY)
207: .toString();
208: } catch (Exception e1) {
209: }
210: }
211: server.log(Server.LOG_WARNING, null, trace);
212: }
213: return;
214: }
215: }
|