001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Sam
028: */
029:
030: package com.caucho.server.rewrite;
031:
032: import com.caucho.config.Config;
033: import com.caucho.config.ConfigException;
034: import com.caucho.util.L10N;
035: import com.caucho.vfs.CaseInsensitive;
036:
037: import javax.servlet.FilterChain;
038: import javax.servlet.ServletException;
039: import java.util.ArrayList;
040: import java.util.logging.Level;
041: import java.util.logging.Logger;
042: import java.util.regex.Matcher;
043: import java.util.regex.Pattern;
044:
045: public abstract class AbstractRuleWithConditions extends AbstractRule {
046: private static final L10N L = new L10N(
047: AbstractRuleWithConditions.class);
048: private static final Logger log = Logger
049: .getLogger(AbstractRuleWithConditions.class.getName());
050:
051: private final boolean _isFiner;
052: private final boolean _isFinest;
053:
054: private Pattern _regexp;
055: private Pattern _urlRegexp;
056:
057: private ArrayList<Condition> _conditionList = new ArrayList<Condition>();
058:
059: private Condition[] _conditions;
060:
061: protected AbstractRuleWithConditions(RewriteDispatch rewriteDispatch) {
062: super (rewriteDispatch);
063:
064: _isFinest = log.isLoggable(Level.FINEST);
065: _isFiner = log.isLoggable(Level.FINER);
066: }
067:
068: /**
069: * Sets the regular expression pattern that must match the uri for the
070: * rule to match, required.
071: */
072: public void setRegexp(Pattern regexp) {
073: _regexp = regexp;
074: }
075:
076: public Pattern getRegexp() {
077: return _regexp;
078: }
079:
080: /**
081: * Sets the regular expression pattern that must match the uri for the
082: * rule to match, required.
083: */
084: public void setFullUrlRegexp(Pattern regexp) {
085: _urlRegexp = regexp;
086: }
087:
088: public Pattern getFullUrlRegexp() {
089: return _urlRegexp;
090: }
091:
092: /**
093: * Add a list of conditions that must pass for the rule to match.
094: */
095: public void addAnd(AndConditions condition) {
096: _conditionList.add(condition);
097: }
098:
099: /**
100: * Add a list of conditions one of which must pass for the rule to match.
101: */
102: public void addOr(OrConditions condition) {
103: _conditionList.add(condition);
104: }
105:
106: /**
107: * Add a list of conditions that must not pass for the rule to match.
108: */
109: public void addNot(NotConditions condition) {
110: _conditionList.add(condition);
111: }
112:
113: /**
114: * Add a condition that must pass for the rule to match.
115: */
116: public void addWhen(ConditionConfig condition) {
117: _conditionList.add(condition.getCondition());
118: }
119:
120: /**
121: * Add a condition that must not pass for the rule to match.
122: */
123: public void addUnless(ConditionConfig condition) {
124: NotConditions not = new NotConditions();
125: not.add(condition.getCondition());
126: Config.init(not);
127:
128: _conditionList.add(not);
129: }
130:
131: /**
132: * Throws an exception if the passed value is null.
133: */
134: protected void required(Object value, String name)
135: throws ConfigException {
136: if (value == null)
137: throw new ConfigException(L
138: .l("{0} requires '{1}' attribute.", getTagName(),
139: name));
140: }
141:
142: @Override
143: public void init() throws ConfigException {
144: if (_regexp != null)
145: setLogPrefix(getLogPrefix() + " " + _regexp.pattern());
146:
147: if (_regexp != null && CaseInsensitive.isCaseInsensitive())
148: _regexp = Pattern.compile(_regexp.pattern(),
149: Pattern.CASE_INSENSITIVE);
150:
151: if (_conditionList.size() > 0) {
152: _conditions = new Condition[_conditionList.size()];
153: _conditionList.toArray(_conditions);
154: }
155:
156: _conditionList = null;
157:
158: super .init();
159: }
160:
161: public FilterChain map(String uri, String queryString,
162: FilterChain accept) throws ServletException {
163:
164: if (!isEnabled()) {
165: if (_isFinest)
166: log.finest(getLogPrefix() + " not enabled, no match");
167:
168: return getFailFilterChainMapper().map(uri, queryString,
169: accept);
170: }
171:
172: Matcher matcher;
173:
174: if (_regexp != null) {
175: matcher = _regexp.matcher(uri);
176:
177: if (!matcher.find()) {
178: if (_isFinest)
179: log.finest(getLogPrefix() + " does not match "
180: + uri);
181:
182: return getFailFilterChainMapper().map(uri, queryString,
183: accept);
184: }
185: } else if (_urlRegexp != null) {
186: String fullUrl;
187:
188: if (queryString != null)
189: fullUrl = uri + '?' + queryString;
190: else
191: fullUrl = uri;
192:
193: matcher = _urlRegexp.matcher(fullUrl);
194:
195: if (!matcher.find()) {
196: return getFailFilterChainMapper().map(uri, queryString,
197: accept);
198: }
199: } else
200: matcher = null;
201:
202: String targetUri = rewrite(uri, matcher);
203:
204: FilterChain ruleChain = dispatch(targetUri, queryString,
205: accept, getPassFilterChainMapper());
206:
207: Condition[] conditions = _conditions;
208:
209: if (conditions == null) {
210: if (_isFiner)
211: log.finer(getLogPrefix() + " '" + uri + "' --> '"
212: + targetUri + "'");
213:
214: if (ruleChain == null)
215: return getPassFilterChainMapper().map(uri, queryString,
216: accept);
217: else
218: return ruleChain;
219: } else {
220: FilterChain passChain = ruleChain;
221:
222: if (passChain == null) {
223: passChain = new ContinueMapFilterChain(targetUri,
224: queryString, accept, getPassFilterChainMapper());
225: }
226:
227: FilterChain failChain = new ContinueMapFilterChain(uri,
228: queryString, accept, getFailFilterChainMapper());
229:
230: return new ConditionFilterChain(getLogPrefix(), uri,
231: targetUri, conditions, passChain, failChain);
232:
233: }
234: }
235:
236: /**
237: * Return a rewritten uri to use for the rest of the processing of
238: * rewrite-dispatch.
239: *
240: * @param matcher a Matcher obtained from doing a regexp comparison, or null
241: * if there was no regexp comparison
242: */
243: public String rewrite(String uri, Matcher matcher) {
244: return uri;
245: }
246:
247: /**
248: * Returns the FilterChain to invoke if the rule is successful, null indicates
249: * that the rule does not invoke a FilterChain.
250: *
251: * @param targetUri the target uri, possibly rewritten
252: * @param accept a FilterChain that stops evaluation of rewrite rules and
253: * @param next
254: */
255: abstract public FilterChain dispatch(String targetUri,
256: String queryString, FilterChain accept,
257: FilterChainMapper next) throws ServletException;
258:
259: @Override
260: public void destroy() {
261: Condition[] conditions = _conditions;
262: _conditions = null;
263:
264: if (conditions != null) {
265:
266: for (Condition condition : conditions) {
267: // XXX: s/b Config.destroy()
268: try {
269: condition.destroy();
270: } catch (Exception ex) {
271: log.log(Level.FINER, ex.toString(), ex);
272: }
273: }
274: }
275:
276: super.destroy();
277: }
278:
279: }
|