/* * Copyright 2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ratpack.retrofit.internal; import okhttp3.*; import okhttp3.Call; import okhttp3.Response; import okio.Buffer; import okio.BufferedSource; import ratpack.exec.Execution; import ratpack.exec.Promise; import ratpack.handling.Context; import ratpack.http.MutableHeaders; import ratpack.http.client.HttpClient; import ratpack.http.client.ReceivedResponse; import ratpack.http.client.RequestSpec; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; public class RatpackCallFactory implements okhttp3.Call.Factory { public static final RatpackCallFactory INSTANCE = new RatpackCallFactory(); private RatpackCallFactory() { } @Override public Call newCall(Request request) { return new RatpackCall(request); } static class RatpackCall implements Call { private final Request request; public RatpackCall(Request request) { this.request = request; } @Override public Request request() { return request; } @Override public Response execute() throws IOException { throw new UnsupportedOperationException("execute() not implemented for Ratpack"); } @Override public void enqueue(okhttp3.Callback responseCallback) { final Call thisCall = this; promise().onError(t -> { if (t instanceof IOException) { responseCallback.onFailure(thisCall, (IOException) t); } else { responseCallback.onFailure(thisCall, new IOException(t)); } }).then(r -> responseCallback.onResponse(thisCall, mapReceivedResponse(r)) ); } Promise<ReceivedResponse> promise() { HttpClient client = Execution.current() .get(Context.class) .get(HttpClient.class); return client.request(request.url().uri(), this::configureRequest); } private void configureRequest(RequestSpec spec) throws Exception { spec.method(request.method()); spec.headers(this::configureHeaders); if (request.body() != null) { spec.body(this::configureBody); } } private void configureHeaders(MutableHeaders h) { for(Map.Entry<String, List<String>> entry : request.headers().toMultimap().entrySet()) { h.set(entry.getKey(), entry.getValue()); } } private void configureBody(RequestSpec.Body b) throws Exception { Buffer buffer = new Buffer(); request.body().writeTo(buffer); b.stream(buffer::writeTo); b.type(request.body().contentType().toString()); } private Response mapReceivedResponse(ReceivedResponse r) { Response.Builder builder = new Response.Builder(); builder.request(request) .code(r.getStatusCode()) .body(new ResponseBody() { @Override public MediaType contentType() { return MediaType.parse(r.getBody().getContentType().toString()); } @Override public long contentLength() { return r.getBody().getBytes().length; } @Override public BufferedSource source() { return new Buffer().write(r.getBody().getBytes()); } }); for (Map.Entry<String, Collection<String>> entry : r.getHeaders().asMultiValueMap().asMultimap().asMap().entrySet()) { for (String value : entry.getValue()) { builder.addHeader(entry.getKey(), value); } } builder.protocol(Protocol.HTTP_1_1); return builder.build(); } @Override public void cancel() { throw new UnsupportedOperationException("cancel() not implemented for Ratpack"); } @Override public boolean isExecuted() { return false; } @Override public boolean isCanceled() { return false; } } }