package org.zalando.riptide; import com.google.gag.annotation.remark.Hack; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.web.client.RestClientException; import java.io.IOException; import java.nio.charset.Charset; import java.util.Optional; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static org.zalando.fauxpas.TryWith.tryWith; @SuppressWarnings("serial") public final class NoRouteException extends RestClientException { private static final int MAX_BODY_BYTES_TO_READ = 8192; private final ClientHttpResponse response; public NoRouteException(final ClientHttpResponse response) throws IOException { super(formatMessage(response)); this.response = response; } private static String formatMessage(final ClientHttpResponse response) throws IOException { return String.format("Unable to dispatch response: %d - %s\n%s\n%s", response.getRawStatusCode(), response.getStatusText(), response.getHeaders(), readStartOfBody(response)); } private static String readStartOfBody(final ClientHttpResponse response) throws IOException { return tryWith(response.getBody(), stream -> { if (stream == null) { return ""; } final byte[] buffer = new byte[MAX_BODY_BYTES_TO_READ]; final int read = stream.read(buffer); if (read == -1) { return ""; } final Charset charset = extractCharset(response); return new String(buffer, 0, read, charset); }); } private static Charset extractCharset(final ClientHttpResponse response) { return Optional.ofNullable(response.getHeaders().getContentType()) .map(NoRouteException::extractCharset) .orElse(ISO_8859_1); } @Hack("MediaType#getCharset is not available prior to Spring 4.3") @SuppressWarnings("deprecation") private static Charset extractCharset(final MediaType mediaType) { return mediaType.getCharSet(); } public ClientHttpResponse getResponse() { return response; } }