001: /*
002: * Copyright (C) 2006 Methodhead Software LLC. All rights reserved.
003: *
004: * This file is part of TransferCM.
005: *
006: * TransferCM is free software; you can redistribute it and/or modify it under the
007: * terms of the GNU General Public License as published by the Free Software
008: * Foundation; either version 2 of the License, or (at your option) any later
009: * version.
010: *
011: * TransferCM is distributed in the hope that it will be useful, but WITHOUT ANY
012: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
013: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
014: * details.
015: *
016: * You should have received a copy of the GNU General Public License along with
017: * TransferCM; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
018: * Fifth Floor, Boston, MA 02110-1301 USA
019: */
020:
021: package com.methodhead.sitecontext;
022:
023: import javax.servlet.Filter;
024: import javax.servlet.FilterConfig;
025: import javax.servlet.ServletResponse;
026: import javax.servlet.ServletRequest;
027: import javax.servlet.FilterChain;
028: import javax.servlet.ServletException;
029: import javax.servlet.http.HttpServletRequest;
030: import java.util.regex.Matcher;
031: import java.util.regex.Pattern;
032: import java.util.Map;
033: import java.util.HashMap;
034: import java.io.IOException;
035: import com.methodhead.sitecontext.SiteContext;
036: import com.methodhead.aikp.IntKey;
037: import com.methodhead.persistable.PersistableException;
038: import com.methodhead.MhfException;
039: import org.apache.commons.lang.StringUtils;
040: import org.apache.log4j.Logger;
041: import org.apache.log4j.Level;
042: import org.apache.commons.lang.exception.ExceptionUtils;
043:
044: public class SiteContextFilter implements Filter {
045:
046: // constructors /////////////////////////////////////////////////////////////
047:
048: // constants ////////////////////////////////////////////////////////////////
049:
050: /**
051: * The URL path the filter identifies with the web app root.
052: */
053: public static final String APPROOT = "approot";
054:
055: /**
056: * The app root wrapped with forward slashes for convenience.
057: */
058: public static final String APPROOTPATH = "/" + APPROOT + "/";
059:
060: // classes //////////////////////////////////////////////////////////////////
061:
062: // methods //////////////////////////////////////////////////////////////////
063:
064: /**
065: * Reads a comma-separated list of Strut module names from the
066: * <code>strutsModules</code> init param.
067: */
068: public void init(FilterConfig filterConfig) throws ServletException {
069:
070: //
071: // set up map of struts modules
072: //
073: String strutsModulesStr = filterConfig
074: .getInitParameter("strutsModules");
075:
076: if (strutsModulesStr == null) {
077: return;
078: }
079:
080: String[] strutsModulesArr = strutsModulesStr.split(",");
081:
082: for (int i = 0; i < strutsModulesArr.length; i++) {
083: strutsModules_
084: .put(strutsModulesArr[i], strutsModulesArr[i]);
085: }
086: }
087:
088: /**
089: * This method is called when no site context can be loaded for the given
090: * URL. By default, <code>chain.doFilter()</code> is called.
091: */
092: protected void processUnknownSiteContext(
093: HttpServletRequest httpRequest, ServletResponse response,
094: FilterChain chain, String path, String pathInfo)
095: throws IOException, ServletException {
096:
097: //
098: // process normally and hope for the best
099: //
100: chain.doFilter(httpRequest, response);
101: }
102:
103: public void doFilter(ServletRequest request,
104: ServletResponse response, FilterChain chain)
105: throws IOException, ServletException {
106:
107: //
108: // get some things we'll need; consider the following url:
109: //
110: // http://site1.com:8080/mhf/subsite/test.txt
111: //
112: HttpServletRequest httpRequest = (HttpServletRequest) request;
113:
114: String sitePath = httpRequest.getRequestURI().substring(
115: httpRequest.getContextPath().length()); // "subsite/test.txt"
116:
117: String domain = httpRequest.getServerName(); // "site1.com"
118:
119: String pathInfo = ""; // "test.txt"
120:
121: String path = ""; // "subsite"
122:
123: SiteContext siteContext = null;
124:
125: //
126: // try to match a site context
127: //
128: if (logger_.isDebugEnabled()) {
129: logger_.debug("Attempting to match domain=\"" + domain
130: + "\" and sitePath=\"" + sitePath + "\".");
131: }
132:
133: siteContext = new SiteContext();
134:
135: //
136: // do we have a sitePath to match?
137: //
138: if (sitePath.length() > 0 && !sitePath.equals("/")) {
139:
140: //
141: // break out the path and pathInfo
142: //
143: Matcher matcher = Pattern.compile(
144: "^(\\/(\\w+))?(\\/(.*))?$").matcher(sitePath);
145:
146: if (!matcher.matches()) {
147: throw new RuntimeException("Couldn't match url \""
148: + domain + sitePath + "\".");
149: }
150:
151: path = matcher.group(2);
152:
153: if (path == null) {
154: path = "";
155: }
156:
157: pathInfo = matcher.group(4);
158:
159: if (pathInfo == null)
160: pathInfo = "";
161: else
162: pathInfo = "/" + pathInfo;
163: }
164:
165: //
166: // is this a Cactus test?
167: //
168: if ("ServletRedirector".equals(path)
169: || "JspRedirector".equals(path)) {
170:
171: if (logger_.isDebugEnabled()) {
172: logger_.debug("Matched Cactus url \"" + path
173: + "\"; filtering normally");
174: }
175:
176: chain.doFilter(request, response);
177: return;
178: }
179:
180: //
181: // is the path one of the Struts modules we know about?
182: //
183: if (strutsModules_.containsKey(path)) {
184:
185: if (logger_.isDebugEnabled()) {
186: logger_.debug("Matched Struts module \"" + path + "\"");
187: }
188:
189: //
190: // get rid of the path
191: //
192: path = "";
193: }
194:
195: //
196: // at this point, path may indicate a sub-site, a subdirectory, or a struts
197: // module; load site context for domain and path?
198: //
199: if (siteContext.loadForDomainAndPath(domain, path)) {
200: if (logger_.isDebugEnabled()) {
201: logger_.debug("Matched domain and path; domain=\""
202: + domain + "\", " + "path=\"" + path + "\"");
203: }
204: }
205:
206: //
207: // maybe path is a subdir; load for just domain?
208: //
209: else if (siteContext.loadForDomainAndPath(domain, "")) {
210:
211: //
212: // didn't use path to determine site context, it must be part of the
213: // pathInfo
214: //
215: pathInfo = "/" + path + pathInfo;
216:
217: if (logger_.isDebugEnabled()) {
218: logger_.debug("Matched domain only; domain=\"" + domain
219: + "\", " + "path=\"" + path + "\"");
220: }
221: } else {
222:
223: if (logger_.isDebugEnabled()) {
224: logger_
225: .debug("Couldn't load site context for domain=\""
226: + domain
227: + "\", "
228: + "path=\""
229: + path
230: + "\"; filtering normally");
231: }
232:
233: //
234: // process an unknown site context
235: //
236: processUnknownSiteContext(httpRequest, response, chain,
237: path, pathInfo);
238: return;
239: }
240:
241: if (logger_.isDebugEnabled()) {
242: logger_.debug("Loaded site context " + siteContext);
243: }
244:
245: //
246: // set request attribute
247: //
248: httpRequest.setAttribute(SiteContext.SITECONTEXT_KEY,
249: siteContext);
250:
251: //
252: // handle the request accordingly
253: //
254: doFilter(httpRequest, response, chain, siteContext, pathInfo);
255: }
256:
257: protected void doFilter(HttpServletRequest httpRequest,
258: ServletResponse response, FilterChain chain,
259: SiteContext siteContext, String pathInfo)
260: throws IOException, ServletException {
261:
262: //
263: // struts action?
264: //
265: if (pathInfo.endsWith(".do")) {
266:
267: //
268: // is there a path?
269: //
270: if (!"".equals(siteContext.getString("path"))) {
271:
272: if (logger_.isDebugEnabled()) {
273: logger_
274: .debug("Handling struts action with a path; forwarding to "
275: + pathInfo);
276: }
277:
278: //
279: // forward to the action without the path
280: //
281: httpRequest.getRequestDispatcher(pathInfo.toString())
282: .forward(httpRequest, response);
283: }
284:
285: //
286: // otherwise, handle the request normally
287: //
288: else {
289: if (logger_.isDebugEnabled()) {
290: logger_.debug("Handling struts action " + pathInfo);
291: }
292:
293: chain.doFilter(httpRequest, response);
294: }
295:
296: return;
297: }
298:
299: //
300: // no pathInfo?
301: //
302: if (pathInfo.equals("") || pathInfo.equals("/")) {
303:
304: if (logger_.isDebugEnabled()) {
305: logger_
306: .debug("Handling empty pathInfo; forwarding to \""
307: + "/"
308: + siteContext.getInt("id")
309: + "/index.jsp\".");
310: }
311:
312: httpRequest.getRequestDispatcher(
313: "/" + siteContext.getInt("id") + "/index.jsp")
314: .forward(httpRequest, response);
315: return;
316: }
317:
318: //
319: // root file (not in any site context)
320: //
321: int i = -1;
322: if ((i = pathInfo.indexOf(APPROOTPATH)) >= 0) {
323:
324: if (logger_.isDebugEnabled()) {
325: logger_.debug("Handling root file; forwarding to \"/"
326: + pathInfo.substring(APPROOTPATH.length()));
327: }
328:
329: httpRequest.getRequestDispatcher(
330: "/" + pathInfo.substring(i + APPROOTPATH.length()))
331: .forward(httpRequest, response);
332: return;
333: }
334:
335: //
336: // normal file; add site context id to site path and forward on
337: //
338: if (logger_.isDebugEnabled()) {
339: logger_.debug("Normal file; forwarding to \"" + "/"
340: + siteContext.getInt("id") + pathInfo + "\".");
341: }
342: httpRequest.getRequestDispatcher(
343: "/" + siteContext.getInt("id") + pathInfo).forward(
344: httpRequest, response);
345: return;
346: }
347:
348: public void destroy() {
349: }
350:
351: // properties ///////////////////////////////////////////////////////////////
352:
353: // attributes ///////////////////////////////////////////////////////////////
354:
355: private static Logger logger_ = Logger
356: .getLogger(SiteContextFilter.class);
357:
358: private Map strutsModules_ = new HashMap();
359: }
|