libreccm-legacy/ccm-cms/src/com/arsdigita/cms/dispatcher/ContentCenterDispatcher.java

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);
}
}
}