/*******************************************************************************
* Copyright (c) 2010-2014 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.skalli.services.extension.rest;
import java.io.IOException;
import java.io.Writer;
import java.text.MessageFormat;
import org.apache.commons.lang.StringUtils;
import org.eclipse.skalli.commons.FormatUtils;
import org.eclipse.skalli.commons.XMLUtils;
import org.eclipse.skalli.services.Services;
import org.eclipse.skalli.services.rest.RequestContext;
import org.eclipse.skalli.services.rest.RestService;
import org.eclipse.skalli.services.rest.RestWriter;
import org.restlet.data.Status;
import org.restlet.representation.WriterRepresentation;
/**
* REST representation for error responses as defined by <tt>/schemas/error.xsd</tt>.
* <p>
* {@link RestExtension Extensions for the REST API} should return error representations
* at least for all kinds of HTTP 5xx server errors, and may return them for HTTP 4xx
* client errors as well.
*/
public class ErrorRepresentation extends WriterRepresentation {
private RequestContext context;
private Status status;
private String errorId;
private String message;
private String timestamp;
/**
* Constructs an error representation with the given status, error identifier and
* detail message.
* <p>
* The error identifier helps tracing the error in the log and distinguishing it from
* other errors produced by the same REST extension.<br>
* The usual format is <tt>rest:<path>:<number%></tt>, e.g.
* <tt>rest:/api/projects/technology.skalli:20</tt>. The <tt><number></tt> distinguishes
* errors for a REST extensions, where "00" is reserved for unexpected errors and
* "10" for i/o errors. All other error numbers are specific for the REST extension.<br>
* The <tt><path></tt> should be the path of the original resource that caused
* the error, but REST extensions may deviate from that convention.
*
* @param context the parameters of the request like media type an host.
* @param status the status of the response, including the status code.
* @param errorId a unique identifier for the error that has happened, or <code>null</code>.
* If no id is specified, one is generated from the status.
* @param message the error message, or <code>null</code>.
* If no message is specified, one is generated from the status.
*/
public ErrorRepresentation(RequestContext context, Status status, String errorId, String message) {
super(context.getMediaType());
this.context = context;
this.status = status;
this.errorId = errorId;
this.message = message;
this.timestamp = FormatUtils.formatUTCWithMillis(System.currentTimeMillis());
}
// for testing purposes
String getTimestamp() {
return timestamp;
}
@Override
public void write(Writer writer) throws IOException {
RestService restService = Services.getRequiredService(RestService.class);
RestWriter restWriter = restService.getRestWriter(writer, context);
restWriter.object("error"); //$NON-NLS-1$
restWriter.namespace(XMLUtils.XMLNS, RestUtils.API_NAMESPACE);
restWriter.namespace(XMLUtils.XMLNS_XSI, XMLUtils.XSI_INSTANCE_NS);
restWriter.namespace(XMLUtils.XSI_SCHEMA_LOCATION, MessageFormat.format(
"{0} {1}/schemas/error.xsd", RestUtils.API_NAMESPACE, context.getHost())); //$NON-NLS-1$
if (StringUtils.isBlank(errorId)) {
errorId = MessageFormat.format("rest:{0}:{1}", context.getPath(), Integer.toString(status.getCode())); //$NON-NLS-1$
}
restWriter.pair("errorId", errorId); //$NON-NLS-1$
restWriter.pair("timestamp", timestamp); //$NON-NLS-1$
if (StringUtils.isBlank(message)) {
message = MessageFormat.format("{0} ({1})", status.getDescription(), status.getName()); //$NON-NLS-1$
}
restWriter.pair("message", message); //$NON-NLS-1$
restWriter.end();
restWriter.flush();
}
}