001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.framework;
011:
012: import java.io.IOException;
013: import java.util.regex.Pattern;
014: import java.util.*;
015:
016: import javax.servlet.*;
017: import javax.servlet.RequestDispatcher;
018: import javax.servlet.http.*;
019:
020: import org.mmbase.util.functions.*;
021: import org.mmbase.servlet.*;
022: import org.mmbase.module.core.*;
023:
024: import org.mmbase.util.logging.Logger;
025: import org.mmbase.util.logging.Logging;
026:
027: /**
028: * Requestfilter that filters out all URL's looking for virtual 'userfriendly' links that have a
029: * corresponding page (technical URL) within the website. When the recieved URL is not
030: * recognized by the framework as an 'userfriendly' one, it just gets forwarded in its original
031: * form. The filtering and conversion to an URL pointing to an existing JSP template is done by
032: * an UrlConverter, of which the framework extends.
033: * Regular expressions that define URL's to be excluded from filtering should be listed in the
034: * 'excludes' parameter in web.xml.
035: *
036: * @author André van Toly
037: * @version $Id: FrameworkFilter.java,v 1.21 2008/02/03 17:33:56 nklasens Exp $
038: */
039:
040: public class FrameworkFilter implements Filter, MMBaseStarter {
041:
042: private static final Logger log = Logging
043: .getLoggerInstance(FrameworkFilter.class);
044:
045: /**
046: * MMBase needs to be started first to be able to load config
047: */
048: private static MMBase mmbase;
049: private Thread initThread;
050:
051: /**
052: * The pattern being used to determine to exclude an URL
053: */
054: private static Pattern excludePattern;
055:
056: /*
057: * Methods that need to be overriden form MMBaseStarter
058: */
059: public MMBase getMMBase() {
060: return mmbase;
061: }
062:
063: public void setMMBase(MMBase mm) {
064: mmbase = mm;
065: }
066:
067: public void setInitException(ServletException se) {
068: // never mind, simply ignore
069: }
070:
071: /**
072: * Initialize the filter, called on webapp startup
073: *
074: * @param config object containing init parameters specified
075: * @throws ServletException thrown when an exception occurs in the web.xml
076: */
077: public void init(FilterConfig config) throws ServletException {
078: log.info("Starting UrlFilter");
079: ServletContext ctx = config.getServletContext();
080: String excludes = config.getInitParameter("excludes");
081: if (excludes != null && excludes.length() > 0) {
082: excludePattern = Pattern.compile(excludes);
083: }
084:
085: /* initialize MMBase if its not started yet */
086: MMBaseContext.init(ctx);
087: MMBaseContext.initHtmlRoot();
088: initThread = new MMBaseStartThread(this );
089: initThread.start();
090:
091: log.info("UrlFilter initialized");
092: }
093:
094: /**
095: * Destroy method
096: */
097: public void destroy() {
098: // nothing needed here
099: }
100:
101: public static String getPath(HttpServletRequest request) {
102: String path = (String) request
103: .getAttribute("javax.servlet.forward.servlet");
104: if (path == null) {
105: path = (String) request
106: .getAttribute("javax.servlet.forward.request_uri");
107: if (path != null)
108: path = path
109: .substring(request.getContextPath().length());
110: }
111: if (path == null) {
112: path = request.getRequestURI();
113: if (path != null)
114: path = path
115: .substring(request.getContextPath().length());
116: }
117: // i think path is always != null now.
118: if (path == null)
119: path = request.getPathInfo();
120:
121: return path;
122: }
123:
124: /**
125: * Filters a request and delegates it to UrlConverter if needed.
126: * URL conversion is only done when the URI does not match one of the excludes in web.xml.
127: * Waits for MMBase to be up.
128: *
129: * @param request incoming request
130: * @param response outgoing response
131: * @param chain a chain object, provided for by the servlet container
132: * @throws ServletException thrown when an exception occurs
133: * @throws IOException thrown when an exception occurs
134: */
135: public void doFilter(ServletRequest request,
136: ServletResponse response, FilterChain chain)
137: throws IOException, ServletException {
138:
139: if (mmbase == null) {
140: if (log.isDebugEnabled())
141: log.debug("Still waiting for MMBase (not initialized)");
142: chain.doFilter(request, response);
143: return;
144: }
145:
146: if (request instanceof HttpServletRequest) {
147:
148: HttpServletRequest req = (HttpServletRequest) request;
149: if (log.isTraceEnabled()) {
150: log.trace("Request URI: " + req.getRequestURI());
151: log.trace("Request URL: " + req.getRequestURL());
152: Enumeration e = request.getAttributeNames();
153: while (e.hasMoreElements()) {
154: String att = (String) e.nextElement();
155: log.trace("attribute " + att + ": "
156: + request.getAttribute(att));
157: }
158: }
159:
160: HttpServletResponse res = (HttpServletResponse) response;
161: String path = getPath(req);
162: if (log.isDebugEnabled())
163: log.debug("Processing path: " + path);
164: if (path != null) {
165: try {
166: if (excludePattern != null
167: && excludePattern.matcher(path).find()) {
168: chain.doFilter(request, response); // url is excluded from further actions
169: return;
170: }
171: } catch (Exception e) {
172: log
173: .fatal("Could not process exclude pattern: "
174: + e);
175: }
176: }
177:
178: // URL is not excluded, pass it to UrlConverter to process and forward the request
179: Framework fw = Framework.getInstance();
180: Parameters params = fw.createParameters();
181: if (params.containsParameter(Parameter.REQUEST)) {
182: params.set(Parameter.REQUEST, req);
183: }
184: if (params.containsParameter(Parameter.RESPONSE)) {
185: params.set(Parameter.RESPONSE, res);
186: }
187: try {
188: String forwardUrl = fw.getInternalUrl(path,
189: req.getParameterMap(), params).toString();
190:
191: if (log.isDebugEnabled()) {
192: log.debug("Received '" + forwardUrl
193: + "' from framework, forwarding.");
194: }
195:
196: if (forwardUrl != null && !forwardUrl.equals("")) {
197: res.setHeader("X-MMBase-forward", forwardUrl);
198: /*
199: * RequestDispatcher: If the path begins with a "/" it is interpreted
200: * as relative to the current context root.
201: */
202: RequestDispatcher rd = request
203: .getRequestDispatcher(forwardUrl);
204: rd.forward(request, response);
205: } else {
206: if (log.isDebugEnabled())
207: log
208: .debug("No matching technical URL, just forwarding: "
209: + path);
210: chain.doFilter(request, response);
211: }
212: } catch (FrameworkException fe) {
213: throw new ServletException(fe);
214: }
215: } else {
216: if (log.isDebugEnabled())
217: log
218: .debug("Request not an instance of HttpServletRequest, therefore no url forwarding");
219: chain.doFilter(request, response);
220: }
221: }
222:
223: }
|