001: /*
002: * UrlMapperHandler.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): cstevens, suhler.
022: *
023: * Version: 1.16
024: * Created by suhler on 00/02/14
025: * Last modified by suhler on 00/12/18 11:24:49
026: */
027:
028: package sunlabs.brazil.handler;
029:
030: import sunlabs.brazil.server.Handler;
031: import sunlabs.brazil.server.Request;
032: import sunlabs.brazil.server.Server;
033: import sunlabs.brazil.util.regexp.Regexp;
034: import sunlabs.brazil.util.Format;
035:
036: import java.io.IOException;
037:
038: /**
039: * Handler for mapping or redirecting url's
040: * Matches url's against a regexp pattern. If it matches, the url
041: * is either rewritten or redirected.
042: * <p>
043: * Properties:
044: * <dl class=props>
045: * <dt>match <dd>The regexp to match a url. May contain constructs
046: * of the form ${xxx}, which are replaced by the value of
047: * <code>request.props</code> for the key <i>xxx</i>
048: * <dt>replace <dd>The url to replace it with. This may contain both
049: * regular expression sub-patterns, such as "\1", or
050: * variables of the form ${..} which are replaced with
051: * the equivalent request properties.
052: * <dt>export <dd>If set, use this as a properties prefix, and set
053: * request properties for each sub-expression in "match".
054: * (E.g. [export]1 [export]2 ...).
055: * <dt>redirect <dd>If set, the request is redirected instead of being rewritten
056: * <dt>ignoreCase <dd>If set, the case of the expression is ignored.
057: * <dt>source <dd>If set, then this string is used instead of the
058: * url as the <i>source</i> of the match. Variable substitution
059: * using ${xxx} is performed on <i>source</i>, which, if unset,
060: * defaults to "${url}". If set, the request property:
061: * "url" is set from the corrosponding field in the request
062: * object. The <i>source</i> property
063: * is obtained at init time, but evaluated (for ${...}) at every
064: * request.
065: * <p>
066: * If constructs of the form !{...} are present, they are treated
067: * the same as for ${...}, expect the values are taken from
068: * the HTTP headers instead of from the request properties.
069: * </dl>
070: *
071: * @author Stephen Uhler
072: * @version 1.16, 00/12/18
073: */
074:
075: public class UrlMapperHandler implements Handler {
076: final static String MATCH = "match";
077: final static String SOURCE = "source";
078: final static String REPLACE = "replace";
079: final static String REDIRECT = "redirect";
080: final static String NOCASE = "ignoreCase";
081: final static String EXPORT = "export";
082:
083: Regexp re = null; // the expression to match
084: String replace; // the replacement string
085: String export; // the prefix for exported submatches
086: String source; // the source for the match
087: boolean redirect = false; // True to redirect instead of rewrite
088:
089: public boolean init(Server server, String prefix) {
090: boolean noCase = (server.props.getProperty(prefix + NOCASE) != null);
091: redirect = (server.props.getProperty(prefix + REDIRECT) != null);
092: replace = server.props.getProperty(prefix + REPLACE);
093: export = server.props.getProperty(prefix + EXPORT);
094: source = server.props.getProperty(prefix + SOURCE);
095: if (replace == null) {
096: server.log(Server.LOG_WARNING, prefix, "missing: "
097: + REPLACE);
098: return false;
099: }
100: String match = server.props.getProperty(prefix + MATCH);
101: if (match == null) {
102: server.log(Server.LOG_WARNING, prefix, "missing: " + MATCH);
103: return false;
104: }
105: match = Format.subst(server.props, match);
106: try {
107: re = new Regexp(match, noCase);
108: } catch (Exception e) {
109: server.log(Server.LOG_WARNING, prefix, "Bad expression:"
110: + e);
111: }
112: return (re != null);
113: }
114:
115: /**
116: * If this request matches the expression, rewrite it.
117: */
118:
119: public boolean respond(Request request) throws IOException {
120: String formatted;
121: if (source != null) {
122: request.props.put("url", request.url);
123: formatted = Format.subst(request.props, source);
124: } else {
125: formatted = request.url;
126: }
127: request.log(Server.LOG_DIAGNOSTIC, null, "Matching "
128: + formatted);
129: String sub = re.sub(formatted, replace);
130: if (sub == null) {
131: return false;
132: }
133: sub = Format.subst(request.props, sub);
134: if (export != null) {
135: String[] parts = new String[re.subspecs()];
136: re.match(request.url, parts);
137: for (int i = 0; i < parts.length; i++) {
138: request.props.put(export + i, parts[i]);
139: }
140: }
141:
142: request.log(Server.LOG_DIAGNOSTIC, null, "Mapping " + formatted
143: + " -> " + sub);
144: if (redirect) {
145: request.redirect(sub, null);
146: return true;
147: } else {
148: request.url = sub;
149: return false;
150: }
151: }
152: }
|