/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.engine.application;
import java.util.logging.Level;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.routing.Filter;
import org.restlet.service.StatusService;
// [excludes gwt]
/**
* Filter associating a response entity based on the status. In order to
* customize the default representation, just subclass this class and override
* the "getRepresentation" method.<br>
* If any exception occurs during the call handling, a "server internal error"
* status is automatically associated to the call. Of course, you can
* personalize the representation of this error. Also, if no status is set
* (null), then the "success OK" status is assumed.
*
* Concurrency note: instances of this class or its subclasses can be invoked by
* several threads at the same time and therefore must be thread-safe. You
* should be especially careful when storing state in member variables.
*
* @author Jerome Louvel
*/
public class StatusFilter extends Filter {
/** Indicates if existing representations should be overwritten. */
private volatile boolean overwriting;
/** The helped status service. */
private volatile StatusService statusService;
/**
* Constructor.
*
* @param context
* The context.
* @param overwriting
* Indicates whether an existing representation should be
* overwritten.
*/
public StatusFilter(Context context, boolean overwriting, String email,
Reference homeRef) {
super(context);
this.overwriting = overwriting;
this.statusService = null;
}
/**
* Constructor from a status service.
*
* @param context
* The context.
* @param statusService
* The helped status service.
*/
public StatusFilter(Context context, StatusService statusService) {
this(context, statusService.isOverwriting(), statusService
.getContactEmail(), statusService.getHomeRef());
this.statusService = statusService;
}
/**
* Allows filtering after its handling by the target Restlet. If the status
* is not set, set {@link org.restlet.data.Status#SUCCESS_OK} by default.
*
* If this is an error status, try to get a representation of it with
* {@link org.restlet.service.StatusService#toRepresentation(Status, Request, Response)}
* .
*
* @param request
* The request to handle.
* @param response
* The response to update.
*/
@Override
public void afterHandle(Request request, Response response) {
// If no status is set, then the "success ok" status is assumed.
if (response.getStatus() == null) {
response.setStatus(Status.SUCCESS_OK);
}
// Do we need to get a representation for the current status?
try {
if (response.getStatus().isError()
&& ((response.getEntity() == null) || isOverwriting())) {
response.setEntity(getStatusService().toRepresentation(
response.getStatus(), request, response));
}
} catch (Exception e) {
getLogger().log(Level.WARNING,
"Unable to get the custom status representation", e);
}
}
/**
* Handles the call by distributing it to the next Restlet. If a throwable
* is caught, the
* {@link org.restlet.service.StatusService#toStatus(Throwable, Request, Response)}
* method is invoked.
*
* @param request
* The request to handle.
* @param response
* The response to update.
* @return The continuation status.
*/
@Override
protected int doHandle(Request request, Response response) {
// Normally handle the call
try {
super.doHandle(request, response);
} catch (Throwable throwable) {
Status status = getStatusService().toStatus(throwable, request,
response);
Level level = Level.INFO;
if (status.isServerError()) {
level = Level.WARNING;
} else if (status.isConnectorError()) {
level = Level.INFO;
} else if (status.isClientError()) {
level = Level.FINE;
}
getLogger().log(level,
"Exception or error caught by status service", throwable);
if (response != null) {
response.setStatus(status);
}
}
return CONTINUE;
}
/**
* Returns the helped status service.
*
* @return The helped status service.
*/
public StatusService getStatusService() {
return statusService;
}
/**
* Indicates if existing representations should be overwritten.
*
* @return True if existing representations should be overwritten.
*/
public boolean isOverwriting() {
return overwriting;
}
/**
* Indicates if existing representations should be overwritten.
*
* @param overwriting
* True if existing representations should be overwritten.
*/
public void setOverwriting(boolean overwriting) {
this.overwriting = overwriting;
}
/**
* Sets the helped status service.
*
* @param statusService
* The helped status service.
*/
public void setStatusService(StatusService statusService) {
this.statusService = statusService;
}
}