001: /*
002: * ResourceHandler.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.19
024: * Created by suhler on 99/07/09
025: * Last modified by suhler on 00/12/11 13:27:31
026: */
027:
028: package sunlabs.brazil.handler;
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: import sunlabs.brazil.util.http.HttpInputStream;
035:
036: import java.io.ByteArrayOutputStream;
037: import java.io.InputStream;
038: import java.io.IOException;
039: import java.io.FileNotFoundException;
040: import java.io.File;
041: import java.io.FileInputStream;
042: import java.util.Properties;
043:
044: /**
045: * Handler for serving documents out of the jar file.
046: *
047: * Look for url's as resources, presumably in the same "jar"
048: * file as the class files.
049: * This allows an entire web site to be included in the jar file.
050: * A typical way to use this handler (with java 1.2+) is as follows:
051: *<ul>
052: *<li>Add an existing web site to the jar file with:
053: * <pre>jar uf [jar file] [web site]</pre>
054: *<li>Create a config file, and add it to the jar file as:
055: * <code>sunlabs/brazil/main/config</code>. See
056: * {@link sunlabs.brazil.server.Main Main.java} for more info.
057: *<li>Create a <i>startup</i> file containing:
058: * <pre>Main-Class: sunlabs.brazil.server.Main</pre>,
059: * and add it to the manifest with:
060: * <pre>jar ufm [jar file] [startup file]</pre>
061: *<li>Start the server with:
062: * <pre>java -jar [jar file] [optional server options....]</pre>
063: *</ul>
064: *
065: *<p>
066: * if no suffix is provided, and the "directory" exists, a redirect
067: * is issued, to add-on the trailing slash.
068: *
069: * The following server properties are used:
070: * <dl class=props>
071: * <dt>root <dd> The document root path within the jar file
072: * <dt>prefix <dd> The url prefix to triger this handler
073: * <dt>default <dd> The default file name for url references ending in /
074: * <dt>mime.xxx <dd> The mime type for suffix xxx.
075: * </dl>
076: *
077: * @author Stephen Uhler
078: * @version %V% ResourceHandler.java
079: */
080:
081: public class ResourceHandler implements Handler {
082: private static final String PREFIX = "prefix";
083: private static final String ROOT = "root";
084: private static final String DEFAULT = "default";
085: private static final String MISSING = "default";
086:
087: String root; // prepend to all url's
088: String urlPrefix; // prefix for our url's
089: String defaultName; // default name for directory url's
090:
091: public boolean init(Server server, String prefix) {
092: urlPrefix = server.props.getProperty(prefix + PREFIX, "/");
093: root = server.props.getProperty(prefix + ROOT, server.props
094: .getProperty(ROOT, "/"));
095: if (!root.endsWith("/")) {
096: root += "/";
097: }
098: defaultName = server.props.getProperty(prefix + DEFAULT,
099: "index.html");
100: return true;
101: }
102:
103: public boolean respond(Request request) throws IOException {
104: if (!request.url.startsWith(urlPrefix)) {
105: return false;
106: }
107: String resource = root + request.url.substring(1);
108: if (resource.endsWith("/")) {
109: resource += defaultName;
110: }
111: request.log(Server.LOG_DIAGNOSTIC, "Looking for resource: "
112: + resource);
113: int index = resource.lastIndexOf(".");
114: String type = "";
115: Class cl = request.getClass();
116: if (index > 0) {
117: String suffix = resource.substring(index + 1);
118: type = request.props.getProperty(FileHandler.MIME + "."
119: + suffix, "");
120: } else if (cl.getResourceAsStream(resource + "/" + defaultName) != null) {
121: request.log(Server.LOG_DIAGNOSTIC,
122: "Redirecting buy adding a /");
123: request.redirect(request.url + "/", null);
124: return true;
125: }
126:
127: request.log(Server.LOG_DIAGNOSTIC, "Resource type: " + type);
128: if (type.equals("")) {
129: request.log(Server.LOG_INFORMATIONAL, request.url
130: + " has an invalid type");
131: return false;
132: }
133: InputStream in = cl.getResourceAsStream(resource);
134: if (in == null) {
135: request.log(Server.LOG_DIAGNOSTIC,
136: "Resource not found in archive");
137: return false;
138: }
139: request.sendResponse(in, -1, type, 200);
140: return true;
141: }
142:
143: private static final Class myClass = ResourceHandler.class;
144:
145: static String getProperty(Properties props, String prefix,
146: String name, String def) {
147: return props.getProperty(prefix + name, props.getProperty(name,
148: def));
149: }
150:
151: static String getResourcePath(Properties props, String prefix,
152: String file) {
153: File f = new File(file);
154: if (f.isAbsolute() == false) {
155: String root = getProperty(props, prefix, FileHandler.ROOT,
156: ".");
157: f = new File(root, file);
158: }
159: return f.getPath();
160: }
161:
162: /**
163: * Look for a file in the filesystem. If its not there, see if
164: * we can find a resource in our jar file. Relative paths
165: * are resolved with respect to the document root.
166: *
167: * @param props where to look for server root property
168: * @param prefix "
169: * @param file The pseudo file to find as a resource
170: * @returns The input stream (or null)
171: */
172:
173: public static InputStream getResourceStream(Properties props,
174: String prefix, String file) throws IOException {
175: String path = getResourcePath(props, prefix, file);
176: File f = new File(path);
177: if (f.isFile()) {
178: return new FileInputStream(f);
179: }
180:
181: /*
182: * Form absolute path and collapse all relative directories;
183: * getResourceAsStream() won't work otherwise.
184: *
185: * File.getCanonicalPath() would be nice to use, but under Windows
186: * it doesn't understand '/' and it prepends a "C:\" to the result.
187: * Class.getResourceAsStream requires '/'.
188: */
189:
190: path = FileHandler.urlToPath(path.replace('\\', '/'));
191: InputStream in = myClass.getResourceAsStream(path.replace('\\',
192: '/'));
193: if (in == null) {
194: throw new FileNotFoundException(file);
195: }
196: return in;
197: }
198:
199: public static String getResourceString(Properties props,
200: String prefix, String file) throws IOException {
201: InputStream in = getResourceStream(props, prefix, file);
202: ByteArrayOutputStream out = new ByteArrayOutputStream();
203: new HttpInputStream(in).copyTo(out);
204: in.close();
205: return out.toString();
206: }
207:
208: /**
209: * Find a file blob as a resource in our jar file (experimental).
210: * @param props where to look for server root property
211: * @param prefix "
212: * @param file The pseudo file to find as a resource
213: * @returns The data, if available, or raises an exception.
214: */
215:
216: public static byte[] getResourceBytes(Properties props,
217: String prefix, String file) throws IOException {
218: InputStream in = getResourceStream(props, prefix, file);
219: ByteArrayOutputStream out = new ByteArrayOutputStream();
220: new HttpInputStream(in).copyTo(out);
221: in.close();
222: return out.toByteArray();
223: }
224: }
|