001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1
003: * The contents of this file are subject to the Mozilla Public License Version
004: * 1.1 (the "License"); you may not use this file except in compliance with
005: * the License. You may obtain a copy of the License at
006: * http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the
011: * License.
012: *
013: * The Original Code is Riot.
014: *
015: * The Initial Developer of the Original Code is
016: * Neteye GmbH.
017: * Portions created by the Initial Developer are Copyright (C) 2007
018: * the Initial Developer. All Rights Reserved.
019: *
020: * Contributor(s):
021: * Felix Gnass [fgnass at neteye dot de]
022: *
023: * ***** END LICENSE BLOCK ***** */
024: package org.riotfamily.pages.mapping;
025:
026: import java.util.ArrayList;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Map;
030:
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpServletResponse;
033:
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036: import org.riotfamily.common.web.controller.HttpErrorController;
037: import org.riotfamily.common.web.controller.RedirectController;
038: import org.riotfamily.common.web.mapping.AbstractReverseHandlerMapping;
039: import org.riotfamily.common.web.mapping.AttributePattern;
040: import org.riotfamily.common.web.util.ServletUtils;
041: import org.riotfamily.pages.dao.PageDao;
042: import org.riotfamily.pages.model.Page;
043: import org.riotfamily.pages.model.PageAlias;
044: import org.riotfamily.pages.model.Site;
045: import org.riotfamily.riot.security.AccessController;
046: import org.springframework.util.AntPathMatcher;
047: import org.springframework.util.Assert;
048: import org.springframework.util.PathMatcher;
049: import org.springframework.web.servlet.HandlerMapping;
050:
051: /**
052: * @author Felix Gnass [fgnass at neteye dot de]
053: * @author Jan-Frederic Linde [jfl at neteye dot de]
054: * @since 6.5
055: */
056: public class PageHandlerMapping extends AbstractReverseHandlerMapping {
057:
058: private static final String PAGE_ATTRIBUTE = PageHandlerMapping.class
059: .getName()
060: + ".page";
061:
062: private static final Log log = LogFactory
063: .getLog(PageHandlerMapping.class);
064:
065: private PathMatcher pathMatcher = new AntPathMatcher();
066:
067: private PageDao pageDao;
068:
069: private PageUrlBuilder pageUrlBuilder;
070:
071: private Object defaultPageHandler;
072:
073: public PageHandlerMapping(PageDao pageDao,
074: PageUrlBuilder pageUrlBuilder) {
075:
076: this .pageDao = pageDao;
077: this .pageUrlBuilder = pageUrlBuilder;
078: }
079:
080: public void setDefaultPageHandler(Object defaultPageHandler) {
081: this .defaultPageHandler = defaultPageHandler;
082: }
083:
084: protected Object getHandlerInternal(HttpServletRequest request)
085: throws Exception {
086:
087: String hostName = request.getServerName();
088: String path = ServletUtils
089: .getOriginatingPathWithoutServletMapping(request);
090: Site site = pageDao.findSite(hostName, path);
091: if (site == null) {
092: return null;
093: }
094: path = site.stripPrefix(path);
095: Page page = pageDao.findPage(site, path);
096: if (page != null) {
097: exposePathWithinMapping(path, request);
098: } else {
099: page = findWildcardPage(site, path);
100: if (page != null) {
101: exposeAttributes(page.getPath(), path, request);
102: exposePathWithinMapping(
103: pathMatcher.extractPathWithinPattern(page
104: .getPath(), path), request);
105: }
106: }
107:
108: log.debug("Page: " + page);
109: if (page != null) {
110: return getPageHandler(page, request);
111: }
112: return getPageNotFoundHandler(site, path);
113: }
114:
115: protected Page findWildcardPage(Site site, String urlPath) {
116: Page page = null;
117: String bestMatch = null;
118: for (Iterator it = pageDao.getWildcardPaths(site).iterator(); it
119: .hasNext();) {
120: String path = (String) it.next();
121: String antPattern = AttributePattern
122: .convertToAntPattern(path);
123: if (pathMatcher.match(antPattern, urlPath)
124: && (bestMatch == null || bestMatch.length() <= path
125: .length())) {
126:
127: bestMatch = path;
128: }
129: }
130: if (bestMatch != null) {
131: page = pageDao.findPage(site, bestMatch);
132: }
133: return page;
134: }
135:
136: /**
137: * Returns the handler for the given page.
138: */
139: protected Object getPageHandler(Page page,
140: HttpServletRequest request) {
141: if (page.isFolder()) {
142: return getFolderHandler(page);
143: }
144: if (isRequestable(page)) {
145: request.setAttribute(PAGE_ATTRIBUTE, page);
146: String handlerName = page.getHandlerName();
147: if (handlerName != null) {
148: exposeHandlerName(handlerName, request);
149: return getApplicationContext().getBean(handlerName);
150: }
151: return defaultPageHandler;
152: }
153: return null;
154: }
155:
156: /**
157: * Returns a Controller that sends a redirect to the request to the first
158: * requestable child page.
159: */
160: private Object getFolderHandler(Page folder) {
161: Iterator it = folder.getChildPages().iterator();
162: while (it.hasNext()) {
163: Page page = (Page) it.next();
164: if (isRequestable(page)) {
165: String url = pageUrlBuilder.getUrl(page);
166: return new RedirectController(url, true, false);
167: }
168: }
169: return null;
170: }
171:
172: /**
173: * Checks if an alias is registered for the given site and path and returns
174: * a RedirectController, or <code>null</code> in case no alias can be found.
175: */
176: protected Object getPageNotFoundHandler(Site site, String path) {
177: PageAlias alias = pageDao.findPageAlias(site, path);
178: if (alias != null) {
179: Page page = alias.getPage();
180: if (page != null) {
181: String url = pageUrlBuilder.getUrl(page);
182: return new RedirectController(url, true, false);
183: } else {
184: return new HttpErrorController(
185: HttpServletResponse.SC_GONE);
186: }
187: }
188: return null;
189: }
190:
191: /**
192: * <strong>Copied from AbstractUrlHandlerMapping</strong>
193: */
194: protected void exposePathWithinMapping(String pathWithinMapping,
195: HttpServletRequest request) {
196: request.setAttribute(
197: HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE,
198: pathWithinMapping);
199: }
200:
201: protected void exposeAttributes(String antPattern, String urlPath,
202: HttpServletRequest request) {
203:
204: AttributePattern pattern = new AttributePattern(antPattern);
205: pattern.expose(urlPath, request);
206: }
207:
208: public static Map getWildcardAttributes(HttpServletRequest request) {
209: return (Map) request
210: .getAttribute(AttributePattern.EXPOSED_ATTRIBUTES);
211: }
212:
213: private boolean isRequestable(Page page) {
214: return page.isEnabled()
215: || AccessController.isAuthenticatedUser();
216: }
217:
218: public static Page getPage(HttpServletRequest request) {
219: return (Page) request.getAttribute(PAGE_ATTRIBUTE);
220: }
221:
222: protected List getPatternsForHandler(String beanName,
223: HttpServletRequest request) {
224:
225: Page currentPage = getPage(request);
226: Assert
227: .notNull(
228: currentPage,
229: "This method can only be used on pages "
230: + "whose handler was resolved by a PageHandlerMapping.");
231:
232: Site site = currentPage.getSite();
233: List pages = pageDao.findPagesForHandler(beanName, site);
234: ArrayList patterns = new ArrayList(pages.size());
235: Iterator it = pages.iterator();
236: while (it.hasNext()) {
237: Page page = (Page) it.next();
238: patterns.add(new AttributePattern(pageUrlBuilder
239: .getUrl(page)));
240: }
241: return patterns;
242: }
243:
244: }
|