296 lines
10 KiB
Java
Executable File
296 lines
10 KiB
Java
Executable File
/*
|
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation; either version 2.1 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
package com.arsdigita.cms.dispatcher;
|
|
|
|
import com.arsdigita.cms.installer.ContentCenterSetup;
|
|
import com.arsdigita.developersupport.DeveloperSupport;
|
|
import com.arsdigita.dispatcher.Dispatcher;
|
|
import com.arsdigita.dispatcher.DispatcherHelper;
|
|
import com.arsdigita.dispatcher.JSPApplicationDispatcher;
|
|
import com.arsdigita.dispatcher.RequestContext;
|
|
import com.arsdigita.kernel.security.Initializer;
|
|
import com.arsdigita.kernel.security.UserContext;
|
|
import com.arsdigita.ui.login.LoginHelper;
|
|
import com.arsdigita.util.LockableImpl;
|
|
import com.arsdigita.web.LoginSignal;
|
|
import com.arsdigita.web.Web;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import javax.servlet.ServletException;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
import org.apache.log4j.Logger;
|
|
|
|
|
|
/**
|
|
* <p> The CMS Workspace Dispatcher serves all request made within the
|
|
* Content Center application. This dispatcher is called by the Subsite
|
|
* dispatcher.</p>
|
|
*
|
|
* <p>Here are the steps for a request to
|
|
* <tt>http://yourserver/content-center/cheese</tt>:</p>
|
|
*
|
|
* <ol>
|
|
* <li><p>A client sends a request to the web server, which passes it on to
|
|
* the global ACS dispatcher.</p></li>
|
|
*
|
|
* <li><p>The global ACS dispatcher examines the first part of the URL,
|
|
* notices that the Content Center application is mounted at
|
|
* <tt>/content-center</tt> and hands the request to the CMS
|
|
* Workspace dispatcher.</p></li>
|
|
*
|
|
* <li><p>The CMS Workspace dispatcher determines whether a <tt>Page</tt>
|
|
* has been registered to the URL <tt>/cheese</tt>.</p></li>
|
|
*
|
|
* <li><p>If no <tt>Page</tt> is registered to the URL <tt>/cheese</tt>,
|
|
* then the CMS Workspace dispatcher hands the request to the
|
|
* {@link com.arsdigita.dispatcher.JSPApplicationDispatcher}.</p></li>
|
|
* </ol>
|
|
*
|
|
* @author Michael Pih (pihman@arsdigita.com)
|
|
* @version $Id: ContentCenterDispatcher.java 1967 2009-08-29 21:05:51Z pboy $
|
|
*/
|
|
public class ContentCenterDispatcher extends LockableImpl
|
|
implements Dispatcher {
|
|
|
|
/**
|
|
* The path of the file that maps resources.
|
|
*/
|
|
public final static String DEFAULT_MAP_FILE = "/WEB-INF/resources/content-center-map.xml";
|
|
|
|
/**
|
|
* Error logging.
|
|
*/
|
|
private static Logger s_log =
|
|
Logger.getLogger(ContentCenterDispatcher.class.getName());
|
|
|
|
/**
|
|
* Mapping between a relative URL and the class name of a
|
|
* ResourceHandler.
|
|
*/
|
|
private static HashMap s_pageClasses = ContentCenterSetup.getURLToClassMap();
|
|
private static HashMap s_pageURLs = ContentCenterSetup.getClassToURLMap();
|
|
|
|
/**
|
|
* Instantiated ResourceHandlers cache. This allows for lazy loading.
|
|
*/
|
|
private static SimpleCache s_pages = new SimpleCache();
|
|
|
|
private Dispatcher m_notFoundHandler;
|
|
private ArrayList m_trailingSlashList = new ArrayList();
|
|
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
public ContentCenterDispatcher() {
|
|
super();
|
|
|
|
m_trailingSlashList = new ArrayList();
|
|
requireTrailingSlash("");
|
|
|
|
setNotFoundDispatcher(JSPApplicationDispatcher.getInstance());
|
|
|
|
//readFromFile(new java.io.File(MAP_FILE));
|
|
}
|
|
|
|
|
|
/**
|
|
* Handles requests made to the Content Center package.
|
|
*
|
|
* @param request The HTTP request
|
|
* @param response The HTTP response
|
|
* @param actx The request context
|
|
*/
|
|
public void dispatch(HttpServletRequest request,
|
|
HttpServletResponse response,
|
|
RequestContext actx)
|
|
throws IOException, ServletException {
|
|
|
|
DeveloperSupport.startStage("ContentCenterDispatcher.dispatch");
|
|
|
|
String url = actx.getRemainingURLPart();
|
|
String originalUrl = actx.getOriginalURL();
|
|
|
|
// Empty remaining URL and doesn't end in trailing slash:
|
|
// probably want to redirect.
|
|
if ( m_trailingSlashList.contains(url) && !originalUrl.endsWith("/") ) {
|
|
DispatcherHelper.sendRedirect(response, originalUrl + "/");
|
|
return;
|
|
}
|
|
|
|
// Check user access.
|
|
checkUserAccess(request, response, actx);
|
|
|
|
ResourceHandler page = getResource(url);
|
|
if ( page != null ) {
|
|
// Serve the page.
|
|
page.init();
|
|
page.dispatch(request, response, actx);
|
|
|
|
DispatcherHelper.maybeCacheDisable(response);
|
|
} else {
|
|
// Fall back on the JSP application dispatcher.
|
|
m_notFoundHandler.dispatch(request, response, actx);
|
|
}
|
|
|
|
DeveloperSupport.endStage("ContentCenterDispatcher.dispatch");
|
|
}
|
|
|
|
/**
|
|
* sets the default page to display if no page can be found for the
|
|
* URL in the page map on dispatch.
|
|
*/
|
|
public final void setNotFoundDispatcher(Dispatcher d) {
|
|
m_notFoundHandler = d;
|
|
}
|
|
|
|
/**
|
|
* Adds a URL to the list of URLs that are required to have trailing
|
|
* slashes. A request for url will be redirected to url + "/"
|
|
* if the original URL request (what you see in your browser)
|
|
* doesn't include a trailing slash. This is required for
|
|
* creating virtual directories, so that relative URLs and redirects
|
|
* work.
|
|
*/
|
|
public void requireTrailingSlash(String url) {
|
|
m_trailingSlashList.add(url);
|
|
}
|
|
|
|
/** Return the URL stub for the class name, can return null if not
|
|
* mapped */
|
|
|
|
public static String getURLStubForClass(String classname) {
|
|
s_log.debug("Getting URL Stub for : " + classname);
|
|
Iterator itr = s_pageURLs.keySet().iterator();
|
|
while (itr.hasNext()) {
|
|
String classname2 = (String)itr.next();
|
|
s_log.debug("key: " + classname + " value: " + (String)s_pageURLs.get(classname2));
|
|
}
|
|
String url = (String)s_pageURLs.get(classname);
|
|
return url;
|
|
}
|
|
|
|
/**
|
|
* Fetch a page based on the URL stub.
|
|
*
|
|
* @param url The URL stub following the site-node URL
|
|
* @return A ResourceHandler or null if none exists.
|
|
* @pre (url != null)
|
|
*/
|
|
protected ResourceHandler getResource(String url) throws ServletException {
|
|
|
|
// First check the pages cache for existing pages.
|
|
ResourceHandler page = (ResourceHandler) s_pages.get(url);
|
|
if ( page == null ) {
|
|
|
|
// Next check if the URL maps to a page class.
|
|
String pageClassName = (String) s_pageClasses.get(url);
|
|
if ( pageClassName != null ) {
|
|
|
|
Class pageClass;
|
|
try {
|
|
pageClass = Class.forName(pageClassName);
|
|
} catch (ClassNotFoundException e) {
|
|
s_log.error("error fetching class for ResourceHandler", e);
|
|
throw new ServletException(e);
|
|
}
|
|
|
|
// Try and instantiate the page.
|
|
try {
|
|
page = (ResourceHandler) pageClass.newInstance();
|
|
} catch (InstantiationException e) {
|
|
s_log.error("error instantiating a ResourceHandler", e);
|
|
throw new ServletException(e);
|
|
} catch (IllegalAccessException e) {
|
|
s_log.error("error instantiating a ResourceHandler", e);
|
|
throw new ServletException(e);
|
|
}
|
|
|
|
page.init();
|
|
s_pages.put(url, page);
|
|
}
|
|
}
|
|
return page;
|
|
}
|
|
|
|
/**
|
|
* Map a page to a URL.
|
|
*
|
|
* @param url The URL
|
|
* @param className The name of the ResourceHandler class
|
|
* @pre (url != null && className != null)
|
|
*/
|
|
protected void addResource(String url, String className) {
|
|
s_pageClasses.put(url, className);
|
|
s_pageURLs.put(className, url);
|
|
}
|
|
|
|
/**
|
|
* Release the page at the specified URL.
|
|
*
|
|
* @param url The URL
|
|
* @pre (url != null)
|
|
*/
|
|
public static void releaseResource(String url) {
|
|
s_pages.remove(url);
|
|
}
|
|
|
|
/**
|
|
* Verify that the user is logged in and is able to view the
|
|
* page. Subclasses can override this method if they need to, but
|
|
* should always be sure to call super.checkUserAccess(...)
|
|
*
|
|
* @param request The HTTP request
|
|
* @param response The HTTP response
|
|
* @param actx The request context
|
|
**/
|
|
protected void checkUserAccess(final HttpServletRequest request,
|
|
final HttpServletResponse response,
|
|
final RequestContext actx)
|
|
throws ServletException {
|
|
if (!Web.getUserContext().isLoggedIn()) {
|
|
throw new LoginSignal(request);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Redirects the client to the login page, setting the return url to
|
|
* the current request URI.
|
|
*
|
|
* @exception ServletException If there is an exception thrown while
|
|
* trying to redirect, wrap that exception in a ServletException
|
|
**/
|
|
protected void redirectToLoginPage(HttpServletRequest req,
|
|
HttpServletResponse resp)
|
|
throws ServletException {
|
|
String url = Initializer.getSecurityHelper()
|
|
.getLoginURL(req)
|
|
+"?"+UserContext.RETURN_URL_PARAM_NAME
|
|
+"="+UserContext.encodeReturnURL(req);
|
|
try {
|
|
LoginHelper.sendRedirect(req, resp, url);
|
|
} catch (IOException e) {
|
|
s_log.error("IO Exception", e);
|
|
throw new ServletException(e.getMessage(), e);
|
|
}
|
|
}
|
|
}
|