/* * Copyright (C) 2002-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.web; import com.arsdigita.dispatcher.InitialRequestContext; import com.arsdigita.dispatcher.DispatcherHelper; import com.arsdigita.dispatcher.RequestContext; import com.arsdigita.domain.DataObjectNotFoundException; import com.arsdigita.kernel.SiteNode; import com.arsdigita.kernel.KernelExcursion; import com.arsdigita.kernel.KernelRequestContext; import com.arsdigita.kernel.security.SessionContext; import com.arsdigita.kernel.security.UserContext; import com.arsdigita.sitenode.SiteNodeRequestContext; import com.arsdigita.util.Assert; import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.web.Application; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import org.apache.log4j.Logger; /** *

The base servlet for CCM applications. It manages database * transactions, prepares an execution context for the request, and * traps and handles requests to redirect.

* *

Most CCM applications will extend this class by implementing * {@link #doService(HttpServletRequest,HttpServletResponse,Application)} to * perform application-private dispatch to UI code.

* * @see com.arsdigita.web.BaseServlet * @see com.arsdigita.web.DispatcherServlet * @see com.arsdigita.web.RedirectSignal * @author Justin Ross <jross@redhat.com> */ public abstract class BaseApplicationServlet extends BaseServlet { public static final String versionId = "$Id: BaseApplicationServlet.java 287 2005-02-22 00:29:02Z sskracic $" + "$Author: sskracic $" + "$DateTime: 2004/08/16 18:10:38 $"; private static Logger s_log = Logger.getLogger (BaseApplicationServlet.class); /** *

The ID of the application whose service is requested. This * request attribute must be set by a previous servlet or filter * before this servlet can proceed. In CCM, the default servlet, * DispatcherServlet, sets this attribute.

*/ public static final String APPLICATION_ID_ATTRIBUTE = BaseApplicationServlet.class.getName() + ".application_id"; /** *

The same as {@link #APPLICATION_ID_ATTRIBUTE}, but as a * request parameter. This is present so applications not using * the dispatcher servlet may accept requests directly to their * servlets, provided the application ID is given in the URL.

*/ public static final String APPLICATION_ID_PARAMETER = "app-id"; /** *

Augments the context of the request and delegates to {@link * #doService(HttpServletRequest,HttpServletResponse,Application)}.

* * @see com.arsdigita.web.BaseServlet#doService(HttpServletRequest,HttpServletResponse) */ protected final void doService(final HttpServletRequest sreq, final HttpServletResponse sresp) throws ServletException, IOException { final Application app = getApplication(sreq); if (app == null) { sresp.sendError(404, "Application not found"); throw new IllegalStateException("Application not found"); } Web.getContext().setApplication(app); final RequestContext rc = makeLegacyContext (sreq, app, Web.getUserContext()); DispatcherHelper.setRequestContext(sreq, rc); final ServletException[] servletException = { null }; final IOException[] ioException = { null }; new KernelExcursion() { protected final void excurse() { setLocale(rc.getLocale()); setResource(app); try { doService(sreq, sresp, app); } catch (ServletException se) { servletException[0] = se; } catch (IOException ioe) { ioException[0] = ioe; } } }.run(); if (servletException[0] != null) { throw servletException[0]; } if (ioException[0] != null) { throw ioException[0]; } } /** *

The method that {@link * #doService(HttpServletRequest,HttpServletResponse)} calls. * Servlet authors should implement this method to perform * application-specific request handling.

* * @see javax.servlet.http.HttpServlet#service(HttpServletRequest,HttpServletResponse) */ protected abstract void doService(HttpServletRequest sreq, HttpServletResponse sresp, Application app) throws ServletException, IOException; private Application getApplication(HttpServletRequest sreq) { s_log.debug("Resolving the application that will handle this request"); BigDecimal id = (BigDecimal) sreq.getAttribute (APPLICATION_ID_ATTRIBUTE); if (id == null) { s_log.debug("I didn't receive an application ID with the " + "servlet request; trying to get it from the " + "query string"); final String value = sreq.getParameter(APPLICATION_ID_PARAMETER); if (value != null) { try { id = new BigDecimal(value); } catch (NumberFormatException nfe) { throw new IllegalStateException ("Could not parse '" + value + "' into a BigDecimal"); } } } Assert.exists(id, "BigDecimal id"); if (s_log.isDebugEnabled()) { s_log.debug("Retrieving application " + id + " from the " + "database"); } return Application.retrieveApplication(id); } /** * * @param sreq * @param app * @param uc * @return */ private RequestContext makeLegacyContext(HttpServletRequest sreq, final Application app, final UserContext uc) { s_log.debug("Setting up a legacy context object"); sreq = DispatcherHelper.restoreOriginalRequest(sreq); final InitialRequestContext irc = new InitialRequestContext (sreq, getServletContext()); final SessionContext sc = uc.getSessionContext(); final KernelRequestContext krc = new KernelRequestContext (irc, sc, uc); SiteNode node = null; try { node = SiteNode.getSiteNode(app.getPrimaryURL(), true); } catch (DataObjectNotFoundException ex) { throw new UncheckedWrapperException("cannot find root sitenode"); } if (node == null) { s_log.debug("There is no site node at this URL; storing a " + "KernelRequestContext"); return krc; } else { s_log.debug("Creating a SiteNodeRequestContext"); final SiteNodeRequestContext snrc = new SiteNodeRequestContext (sreq, krc, node, sreq.getServletPath() + "/"); return snrc; } } }