package org.zalando.riptide;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMessage;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.zalando.fauxpas.ThrowingConsumer;
import org.zalando.fauxpas.ThrowingFunction;
import org.zalando.fauxpas.ThrowingRunnable;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import static com.google.common.base.Throwables.propagateIfPossible;
import static org.zalando.fauxpas.TryWith.tryWith;
@FunctionalInterface
public interface Route {
void execute(final ClientHttpResponse response, final MessageReader reader) throws Exception;
static Route call(final ThrowingRunnable<? extends Exception> runnable) {
return (response, reader) ->
tryWith(response, (ClientHttpResponse _) -> runnable.tryRun());
}
static Route call(final ThrowingConsumer<ClientHttpResponse, ? extends Exception> consumer) {
return (response, reader) ->
tryWith(response, consumer);
}
static <I> Route call(final Class<I> type, final ThrowingConsumer<I, ? extends Exception> consumer) {
return call(TypeToken.of(type), consumer);
}
static <I> Route call(final TypeToken<I> type, final ThrowingConsumer<I, ? extends Exception> consumer) {
return (response, reader) -> {
final I body = reader.read(type, response);
consumer.tryAccept(body);
};
}
static <T> TypeToken<List<T>> listOf(final Class<T> entityType) {
return listOf(TypeToken.of(entityType));
}
@SuppressWarnings("serial")
static <T> TypeToken<List<T>> listOf(final TypeToken<T> entityType) {
final TypeToken<List<T>> listType = new TypeToken<List<T>>() {
// nothing to implement!
};
final TypeParameter<T> elementType = new TypeParameter<T>() {
// nothing to implement!
};
return listType.where(elementType, entityType);
}
static <T> TypeToken<ResponseEntity<T>> responseEntityOf(final Class<T> entityType) {
return responseEntityOf(TypeToken.of(entityType));
}
static <T> TypeToken<ResponseEntity<T>> responseEntityOf(final TypeToken<T> entityType) {
final TypeToken<ResponseEntity<T>> responseEntityType = new TypeToken<ResponseEntity<T>>() {
// nothing to implement!
};
final TypeParameter<T> elementType = new TypeParameter<T>() {
// nothing to implement!
};
return responseEntityType.where(elementType, entityType);
}
static ThrowingConsumer<ClientHttpResponse, RuntimeException> pass() {
return response -> {
// nothing to do!
};
}
static ThrowingFunction<ClientHttpResponse, HttpHeaders, IOException> headers() {
return HttpMessage::getHeaders;
}
static ThrowingFunction<ClientHttpResponse, URI, IOException> location() {
return response ->
response.getHeaders().getLocation();
}
static ThrowingConsumer<ClientHttpResponse, IOException> noRoute() {
return response -> {
throw new NoRouteException(response);
};
}
static <X extends Exception> ThrowingConsumer<X, IOException> propagate() {
return entity -> {
propagateIfPossible(entity, IOException.class);
throw new IOException(entity);
};
}
static <T> Adapter<ClientHttpResponse, T> to(
final ThrowingFunction<ClientHttpResponse, T, ? extends Exception> function) {
return consumer ->
response -> consumer.tryAccept(function.tryApply(response));
}
@FunctionalInterface
interface Adapter<T, R> {
ThrowingConsumer<T, Exception> andThen(final ThrowingConsumer<R, ? extends Exception> consumer);
}
}