001: /*
002: * TemplateHandler.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 1998-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.32
024: * Created by suhler on 98/09/14
025: * Last modified by suhler on 00/12/11 13:30:04
026: */
027:
028: package sunlabs.brazil.template;
029:
030: import sunlabs.brazil.server.FileHandler;
031: import sunlabs.brazil.server.Handler;
032: import sunlabs.brazil.server.Request;
033: import sunlabs.brazil.server.Server;
034:
035: import java.io.File;
036: import java.io.FileInputStream;
037: import java.io.IOException;
038: import java.util.Properties;
039:
040: /**
041: * The <code>TemplateHandler</code> reads a template file from
042: * the document root, based on the URL, and passes the content through
043: * one or more template filters.
044: * <p>
045: * The following configuration parameters are used to initialize this
046: * <code>Handler</code>: <dl class=props>
047: *
048: * <dt> <code>prefix</code>
049: * <dd> Only URLs beginning with this string will be candidates for
050: * template processing. The default is "/".
051: * <dt> <code>suffix</code>
052: * <dd> Suffix string for our requests.
053: * <dt> <code>templates</code>
054: * <dd> A list of <code>Template</code> class names.
055: * Methods in the template classes will
056: * be invoked to process the XML (or HTML) tags present in the content.
057: * <dt> <code>session</code>
058: * <dd> The name of the request property that the Session ID will be found
059: * in, used to identify the proper template instance.
060: * The default value is "SessionID". Typically, a sessionHandler,
061: * such as {@link sunlabs.brazil.handler.CookieSessionHandler} is used
062: * upstream to create the sessionID. If no id is found, then the
063: * session named "common" is used instead. Exactly one instance of
064: * each template class is created for each session.
065: * <dt> <code>default</code>
066: * <dd> The default file in the directory to use as a template if
067: * a directory name is specified. Defaults to index[suffix],
068: * or "index.html" if no suffix is provided.
069: *
070: * </dl>
071: * <p>The request properties <code>DirectoryName</code> and
072: * <code>FileName</code> may be set as a convinience for downstream handlers.
073: * <p>
074: * To filter content other than from the file system, use the
075: * {@link sunlabs.brazil.filter.TemplateFilter template filter} instead.
076: *
077: * @author Stephen Uhler (stephen.uhler@sun.com)
078: * @author Colin Stevens (colin.stevens@sun.com)
079: * @version 1.32 00/12/11
080: */
081:
082: public class TemplateHandler implements Handler {
083: static final String PREFIX = "prefix"; // url prefix
084: static final String SUFFIX = "suffix"; // property for suffix string
085: static final String HANDLER = "handler";
086: static final String TEMPLATES = "templates"; // the class to process these templates
087: static final String SESSION = "session";
088: static final String DEFAULT = "default"; // property for default document, given directory
089:
090: Server server; // a reference to our server
091: String propsPrefix; // our perfix in the config file
092: String sessionProperty; // where to find the session name
093:
094: String urlPrefix = "/"; // which URL's to look for
095: Handler handler;
096: TemplateRunner runner; // The template object for our class
097:
098: public boolean init(Server server, String propsPrefix) {
099: String str;
100:
101: this .server = server;
102: this .propsPrefix = propsPrefix;
103:
104: Properties props = server.props;
105: urlPrefix = props.getProperty(propsPrefix + PREFIX, urlPrefix);
106: sessionProperty = props.getProperty(propsPrefix + SESSION,
107: "SessionID");
108:
109: /*
110: * Gather the templates.
111: */
112:
113: str = server.props.getProperty(propsPrefix + TEMPLATES);
114: if (str == null) {
115: server.log(Server.LOG_ERROR, propsPrefix, "no " + TEMPLATES
116: + " property specified");
117: return false;
118: }
119:
120: try {
121: runner = new TemplateRunner(str);
122: } catch (ClassCastException e) {
123: server.log(Server.LOG_ERROR, e.getMessage(),
124: "not a Template");
125: } catch (ClassNotFoundException e) {
126: server.log(Server.LOG_ERROR, e.getMessage(),
127: "unknown class");
128: return false;
129: }
130: return true;
131: }
132:
133: /**
134: * Process an html template file, using the supplied template
135: * processing classes.
136: */
137:
138: public boolean respond(Request request) throws IOException {
139: if (request.url.startsWith(urlPrefix) == false) {
140: return false;
141: }
142:
143: Properties props = request.props;
144:
145: String suffix = props.getProperty(propsPrefix + SUFFIX, "");
146: if (request.url.endsWith(suffix) == false) {
147: return false;
148: }
149:
150: /*
151: * Now read in the template. There should be a way of
152: * indicating a "false" return, letting another handler handle
153: * This.
154: */
155:
156: String root = props.getProperty(propsPrefix + FileHandler.ROOT,
157: props.getProperty(FileHandler.ROOT, "."));
158:
159: /*
160: * XX This functionality doesn't belong here: Use
161: * the DefaultFileHandler instead.
162: */
163:
164: String name = FileHandler.urlToPath(request.url);
165: File file = new File(root + name);
166: if (file.isDirectory()) {
167: if (request.url.endsWith("/") == false) {
168: request.redirect(request.url + "/", null);
169: request.log(Server.LOG_DIAGNOSTIC, propsPrefix,
170: "redirecting");
171: return true;
172: }
173: props.put("DirectoryName", file.getPath());
174: String base = props.getProperty(propsPrefix + DEFAULT);
175: if (base == null) {
176: base = (suffix.equals("")) ? "index.html" : "index"
177: + suffix;
178: }
179: file = new File(file, base);
180: }
181: props.put("FileName", file.getPath());
182: request.log(Server.LOG_DIAGNOSTIC, propsPrefix,
183: "Looking for template file: " + file.getPath());
184:
185: String content;
186: try {
187: content = getContent(request, file);
188: } catch (IOException e) {
189: request
190: .log(Server.LOG_WARNING, propsPrefix, e
191: .getMessage());
192: return false;
193: }
194:
195: String session = props.getProperty(sessionProperty, "common");
196: request.log(Server.LOG_DIAGNOSTIC, propsPrefix,
197: "Using session (" + session + ")");
198: String result = runner.process(server, propsPrefix, request,
199: content, session);
200: if (result != null) {
201: request.sendResponse(result);
202: return true;
203: } else {
204: request.log(Server.LOG_INFORMATIONAL, propsPrefix, runner
205: .getError());
206: return false;
207: }
208: }
209:
210: /**
211: * get the content associated with this template.
212: * This version reads it from a file.
213: *
214: * @param request The standard request object
215: * @param file The file object to get the template from
216: * @returns The content of the template to be processed
217: */
218:
219: public String getContent(Request request, File file)
220: throws IOException {
221: FileInputStream in = new FileInputStream(file);
222: byte[] buf = new byte[in.available()];
223: in.read(buf);
224: in.close();
225: return new String(buf);
226: }
227: }
|