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.config.types.Period;
035: import com.caucho.loader.Environment;
036: import com.caucho.management.server.RewriteImportMXBean;
037: import com.caucho.util.Alarm;
038: import com.caucho.util.AlarmListener;
039: import com.caucho.util.L10N;
040: import com.caucho.vfs.Depend;
041: import com.caucho.vfs.Path;
042: import com.caucho.jmx.Description;
043:
044: import javax.servlet.FilterChain;
045: import javax.servlet.ServletException;
046: import java.util.logging.Level;
047: import java.util.logging.Logger;
048:
049: public class ImportRule extends AbstractRule implements AlarmListener {
050: private static L10N L = new L10N(ImportRule.class);
051: private static Logger log = Logger.getLogger(ImportRule.class
052: .getName());
053:
054: private Path _path;
055: private boolean _isOptional;
056: private long _dependencyCheckInterval = 2 * 1000L;
057: private long _errorCheckInterval = 2 * 1000L;
058:
059: private Depend _depend;
060:
061: private volatile MatchRule _matchRule;
062: private volatile boolean _isError;
063: private volatile String _redeployError;
064: private volatile boolean _isDestroyed = false;
065: private Alarm _alarm;
066:
067: protected ImportRule(RewriteDispatch rewriteDispatch) {
068: super (rewriteDispatch);
069:
070: _dependencyCheckInterval = Environment
071: .getDependencyCheckInterval();
072: }
073:
074: public String getTagName() {
075: return "import";
076: }
077:
078: public void setDependencyCheckInterval(
079: Period dependencyCheckInterval) {
080: _dependencyCheckInterval = dependencyCheckInterval.getPeriod();
081: }
082:
083: public long getDependencyCheckInterval() {
084: return _dependencyCheckInterval;
085: }
086:
087: public String getRedeployError() {
088: return _redeployError;
089: }
090:
091: public void setOptional(boolean isOptional) {
092: _isOptional = isOptional;
093: }
094:
095: public void setPath(Path path) {
096: _path = path;
097: }
098:
099: @Override
100: public void init() {
101: if (_path == null)
102: throw new ConfigException(L
103: .l("'path' attribute missing from resin:import."));
104:
105: if (getName() == null)
106: setName(_path.getNativePath());
107:
108: try {
109: load();
110: } catch (ConfigException e) {
111: throw e;
112: } catch (Exception e) {
113: throw ConfigException.create(e);
114: }
115:
116: super .init();
117:
118: _alarm = new Alarm("rewrite-dispatch-import", this ,
119: _dependencyCheckInterval);
120: }
121:
122: @Override
123: protected RewriteRuleAdmin createAdmin() {
124: return new RewriteImportAdmin(this );
125: }
126:
127: public void setPassFilterChainMapper(
128: FilterChainMapper passFilterChainMapper) {
129: super .setPassFilterChainMapper(passFilterChainMapper);
130:
131: if (_matchRule != null)
132: _matchRule.setPassFilterChainMapper(passFilterChainMapper);
133: }
134:
135: public void setFailFilterChainMapper(
136: FilterChainMapper failFilterChainMapper) {
137: super .setFailFilterChainMapper(failFilterChainMapper);
138:
139: if (_matchRule != null)
140: _matchRule.setFailFilterChainMapper(failFilterChainMapper);
141: }
142:
143: public FilterChain map(String uri, String query, FilterChain accept)
144: throws ServletException {
145: if (isEnabled() && _matchRule != null)
146: return _matchRule.map(uri, query, accept);
147: else if (getPassFilterChainMapper() != null)
148: return getPassFilterChainMapper().map(uri, query, accept);
149: else
150: return accept;
151: }
152:
153: private synchronized void load() throws Exception {
154: if (_isDestroyed)
155: return;
156:
157: if (_depend != null && !_depend.isModified())
158: return;
159:
160: try {
161: _depend = new Depend(_path);
162:
163: _isError = true;
164:
165: MatchRule matchRule = new MatchRule(getRewriteDispatch());
166: matchRule
167: .setPassFilterChainMapper(getPassFilterChainMapper());
168: matchRule
169: .setFailFilterChainMapper(getFailFilterChainMapper());
170:
171: if (_path.canRead() && !_path.isDirectory()) {
172: } else if (_isOptional) {
173: log.finer(L.l("import '{0}' is not readable.", _path));
174:
175: matchRule.init();
176:
177: _isError = false;
178:
179: setMatchRule(matchRule);
180:
181: return;
182: } else {
183: throw new ConfigException(
184: L
185: .l(
186: "Required file '{0}' can not be read for import.",
187: _path.getNativePath()));
188: }
189:
190: Config config = new Config();
191:
192: config.configure(matchRule, _path);
193:
194: _isError = false;
195:
196: setMatchRule(matchRule);
197: } finally {
198: clearCache();
199: }
200: }
201:
202: private void setMatchRule(MatchRule matchRule) {
203: MatchRule oldMatchRule = _matchRule;
204:
205: if (oldMatchRule != null)
206: oldMatchRule.unregister();
207:
208: matchRule.register();
209:
210: _matchRule = matchRule;
211:
212: if (oldMatchRule != null)
213: oldMatchRule.destroy();
214: }
215:
216: public void handleAlarm(Alarm alarm) {
217: alarm = _alarm;
218:
219: if (_isDestroyed)
220: return;
221:
222: try {
223: _redeployError = null;
224:
225: load();
226: } catch (Exception ex) {
227: _redeployError = ex.toString();
228:
229: log.log(Level.WARNING, ex.toString(), ex);
230: } finally {
231: if (!_isDestroyed) {
232: long delta = _isError ? _errorCheckInterval
233: : _dependencyCheckInterval;
234:
235: alarm.queue(delta);
236: }
237: }
238: }
239:
240: private void update() {
241: handleAlarm(null);
242: }
243:
244: @Override
245: public void destroy() {
246: try {
247: _isDestroyed = true;
248:
249: Alarm alarm = _alarm;
250: _alarm = null;
251:
252: MatchRule matchRule = _matchRule;
253: _matchRule = null;
254:
255: if (alarm != null)
256: alarm.dequeue();
257:
258: if (matchRule != null)
259: matchRule.destroy();
260:
261: } finally {
262: super .destroy();
263: }
264: }
265:
266: public static class RewriteImportAdmin extends RewriteRuleAdmin
267: implements RewriteImportMXBean {
268: private final ImportRule _rule;
269:
270: public RewriteImportAdmin(ImportRule rule) {
271: super (rule);
272:
273: _rule = rule;
274: }
275:
276: @Override
277: public String getType() {
278: return "RewriteImport";
279: }
280:
281: public long getDependencyCheckInterval() {
282: return _rule.getDependencyCheckInterval();
283: }
284:
285: public String getRedeployError() {
286: return _rule.getRedeployError();
287: }
288:
289: @Description("Updates the imported rules if the file has changed")
290: public void update() {
291: _rule.update();
292: }
293: }
294: }
|