/*
* Weblounge: Web Content Management System
* Copyright (c) 2003 - 2011 The Weblounge Team
* http://entwinemedia.com/weblounge
*
* This program 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
* of the License, or (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package ch.entwine.weblounge.dispatcher.impl;
import ch.entwine.weblounge.common.request.WebloungeRequest;
import ch.entwine.weblounge.common.request.WebloungeResponse;
import ch.entwine.weblounge.dispatcher.DispatchListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
/**
* Utility class for error reporting using <code>HttpServletResponse</code>.
*/
public final class DispatchUtils {
/** Logging facility */
private static final Logger logger = LoggerFactory.getLogger(DispatchUtils.class);
/** List of dispatcher listeners */
private static final List<DispatchListener> dispatcher = new ArrayList<DispatchListener>();
/**
* This class is not intended to be instantiated.
*/
private DispatchUtils() {
// Nothing to be done here
}
/**
* Asks the client to do <code>HTTP</code> authentication by sending back the
* <code>WWW-Authenticate</code> header together with the given realm, that
* will label the authentication dialog.
*
* @param request
* the request
* @param response
* the response
* @param realm
* name of the authentication realm
*/
public static void requireAuthentication(WebloungeRequest request,
WebloungeResponse response, String realm) {
StringBuffer authHeader = new StringBuffer("Basic realm=\"");
authHeader.append(realm);
authHeader.append("\"");
response.setHeader("WWW-Authenticate", authHeader.toString());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
/**
* Forward servlet request and servlet response objects, using either a
* registered dispatcher or the request dispatcher contained in the context.
*
* @param request
* Servlet request
* @param response
* Servlet response
* @param url
* target url
*/
public static void forward(WebloungeRequest request,
WebloungeResponse response, String url) throws ServletException,
IOException {
// Remove the url attribute to prevent loops. By removing, The Request
// object
// is forced to evaluate the url again.
request.removeAttribute(WebloungeRequest.URL);
// Ask registered listeners whether they want to redirect the url.
// TODO: Are DispatchListeners still used?
for (int i = 0; i < dispatcher.size(); i++) {
DispatchListener d = dispatcher.get(i);
url = d.redirect(url, request, response);
}
// Ask registered listeners whether they are willing to do the work for us
for (int i = 0; i < dispatcher.size(); i++) {
DispatchListener d = dispatcher.get(i);
if (d.forward(request, response, url))
return;
}
// If we get here, then no dispatcher seems to be responsible for handling
// the request.
logger.debug("No dispatch listener took the request.");
sendError(HttpServletResponse.SC_NOT_FOUND, null, request, response);
}
/**
* Include servlet request and servlet response objects, using the request
* dispatcher contained in the context. Please be careful: use only context
* relative path.
*
* @param request
* Servlet request.
* @param response
* Servlet response.
* @param url
* the url to include
*/
public static void include(WebloungeRequest request,
WebloungeResponse response, String url) throws ServletException,
IOException {
// Remove the url attribute to prevent loops. By removing, The Request
// object is forced to evaluate the url again.
request.removeAttribute(WebloungeRequest.URL);
// Ask registered listeners whether they want to redirect the url.
// TODO: Are DispatchListeners still used?
for (int i = 0; i < dispatcher.size(); i++) {
DispatchListener d = dispatcher.get(i);
url = d.redirect(url, request, response);
}
// Ask registered listeners whether they are willing to do the work for us
for (int i = 0; i < dispatcher.size(); i++) {
DispatchListener d = dispatcher.get(i);
if (d.include(request, response, url))
return;
}
// If we get here, then no dispatcher seems to be responsible for handling
// the request.
logger.debug("No dispatch listener took the request.");
sendError(HttpServletResponse.SC_NOT_FOUND, null, request, response);
}
/**
* Sends a <code>304 - Not modified</code> message back to the client.
*
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendNotModified(WebloungeRequest request,
WebloungeResponse response) {
sendStatus(HttpServletResponse.SC_NOT_MODIFIED, request, response);
}
/**
* Sends a <code>500 - Internal server error</code> message back to the
* client.
*
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendInternalError(WebloungeRequest request,
WebloungeResponse response) {
sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, request, response);
}
/**
* Sends a <code>500 - Internal server error</code> message back to the
* client.
*
* @param msg
* the error message
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendInternalError(String msg, WebloungeRequest request,
WebloungeResponse response) {
sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg, request, response);
}
/**
* Sends a <code>503 - Service Unavailable error</code> message back to the
* client.
*
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendServiceUnavailable(WebloungeRequest request,
WebloungeResponse response) {
sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, null, request, response);
}
/**
* Sends a <code>503 - Service Unavailable error</code> message back to the
* client.
*
* @param msg
* the error message
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendServiceUnavailable(String msg,
WebloungeRequest request, WebloungeResponse response) {
sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, msg, request, response);
}
/**
* Sends a <code>404 - Url not found</code> message back to the client.
*
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendNotFound(WebloungeRequest request,
WebloungeResponse response) {
sendError(HttpServletResponse.SC_NOT_FOUND, null, request, response);
}
/**
* Sends a <code>404 - Url not found</code> message back to the client.
*
* @param msg
* the error message
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendNotFound(String msg, WebloungeRequest request,
WebloungeResponse response) {
sendError(HttpServletResponse.SC_NOT_FOUND, msg, request, response);
}
/**
* Sends a <code>403 - Forbidden</code> message back to the client.
*
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendAccessDenied(WebloungeRequest request,
WebloungeResponse response) {
sendError(HttpServletResponse.SC_FORBIDDEN, null, request, response);
}
/**
* Sends a <code>403 - Forbidden</code> message back to the client.
*
* @param msg
* the error message
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendAccessDenied(String msg, WebloungeRequest request,
WebloungeResponse response) {
sendError(HttpServletResponse.SC_FORBIDDEN, msg, request, response);
}
/**
* Sends a <code>400 - Bad Request</code> message back to the client.
*
* @param msg
* the error message
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendBadRequest(String msg, WebloungeRequest request,
WebloungeResponse response) {
sendError(HttpServletResponse.SC_BAD_REQUEST, msg, request, response);
}
/**
* Sends a <code>400 - Bad Request</code> message back to the client.
*
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendBadRequest(WebloungeRequest request,
WebloungeResponse response) {
sendError(HttpServletResponse.SC_BAD_REQUEST, null, request, response);
}
/**
* Sends the response status <code>status</code> back to the client.
*
* @param status
* the response status
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendStatus(int status, WebloungeRequest request,
WebloungeResponse response) {
try {
if (!response.isCommitted()) {
response.setStatus(status);
}
} catch (Throwable t) {
logger.debug("Unable to send response status {} to client", status);
}
}
/**
* Sends an error message with code <code>status</code> and the according
* error message as the http response.
*
* @param status
* the http status code
* @param msg
* the error message
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendError(int status, WebloungeRequest request,
WebloungeResponse response) {
status = status > 0 ? status : HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
sendError(status, null, request, response);
}
/**
* Sends an error message with code <code>status</code> and the according
* error message as the http response.
*
* @param status
* the http status code
* @param msg
* the error message
* @param request
* the servlet request
* @param response
* the response object
*/
public static void sendError(int status, String msg,
WebloungeRequest request, WebloungeResponse response) {
try {
response.invalidate();
if (!response.isCommitted()) {
response.sendError(status, msg);
}
} catch (Throwable t) {
logger.debug("Error when sending back error message {}: {}", status, t.getMessage());
}
}
/**
* Adds <code>listener</code> to the list of dispatch listeners if it has not
* already been registered. The listener is called every time the current
* request is internally being included or forwarded using the
* <code>include</code> or <code>forward</code> method of this class.
*
* @param listener
* the lister
*/
public static void addDispatchListener(DispatchListener listener) {
if (!dispatcher.contains(listener)) {
dispatcher.add(listener);
}
}
/**
* Removes the listener from the list of request listeners.
*
* @param listener
* the listener to remove
*/
public static void removeDispatchListener(DispatchListener listener) {
dispatcher.remove(listener);
}
}