ProvidenceErrorHandler.java

package net.morimekta.providence.server;

import net.morimekta.providence.serializer.DefaultSerializerProvider;
import net.morimekta.providence.serializer.Serializer;
import net.morimekta.providence.serializer.SerializerProvider;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.QuotedQualityCSV;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.ErrorHandler;

import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class ProvidenceErrorHandler extends ErrorHandler {
    private final SerializerProvider provider;

    public ProvidenceErrorHandler() {
        this(new DefaultSerializerProvider());
    }

    public ProvidenceErrorHandler(@Nonnull SerializerProvider provider) {
        this.provider = provider;
    }

    @Override
    protected void generateAcceptableResponse(Request baseRequest,
                                              HttpServletRequest request,
                                              HttpServletResponse response,
                                              int code,
                                              String message) throws IOException {
        if (response.isCommitted()) return;

        List<String> acceptable = baseRequest
                .getHttpFields()
                .getQualityCSV(HttpHeader.ACCEPT, QuotedQualityCSV.MOST_SPECIFIC_MIME_ORDERING);
        for (String accept : acceptable) {
            try {
                sendResponse(provider.getSerializer(accept), response, code, message);
                return;
            } catch (Exception e) {
                // ignore.
            }
        }

        String contentType = request.getHeader(HttpHeader.CONTENT_TYPE.toString());
        if (contentType != null) {
            try {
                sendResponse(provider.getSerializer(contentType), response, code, message);
                return;
            } catch (Exception e) {
                // ignore.
            }
        }

        sendResponse(provider.getDefault(), response, code, message);
    }

    @Override
    protected void generateAcceptableResponse(Request baseRequest,
                                              HttpServletRequest request,
                                              HttpServletResponse response,
                                              int code,
                                              String message,
                                              String mimeType) throws IOException {
        if (response.isCommitted()) return;

        List<String> acceptable = baseRequest
                .getHttpFields()
                .getQualityCSV(HttpHeader.ACCEPT, QuotedQualityCSV.MOST_SPECIFIC_MIME_ORDERING);
        for (String accept : acceptable) {
            try {
                sendResponse(provider.getSerializer(accept), response, code, message);
                return;
            } catch (Exception e) {
                // ignore.
            }
        }

        String contentType = request.getHeader(HttpHeader.CONTENT_TYPE.toString());
        if (contentType != null) {
            try {
                sendResponse(provider.getSerializer(contentType), response, code, message);
                return;
            } catch (Exception e) {
                // ignore.
            }
        }

        try {
            sendResponse(provider.getSerializer(mimeType), response, code, message);
        } catch (Exception e) {
            sendResponse(provider.getDefault(), response, code, message);
        }
    }

    private void sendResponse(Serializer serializer, HttpServletResponse response, int code, String message) throws IOException {
        response.setStatus(code);
        serializer.serialize(response.getOutputStream(),
                             ProvidenceHttpError.builder()
                                                .setStatusCode(code)
                                                .setMessage(message)
                                                .build());
    }
}