001package org.conqat.engine.service.shared.client;
002
003import java.io.IOException;
004
005import org.apache.http.HttpHeaders;
006import org.apache.http.client.HttpClient;
007import org.apache.http.client.methods.HttpDelete;
008import org.apache.http.client.methods.HttpGet;
009import org.apache.http.client.methods.HttpPost;
010import org.apache.http.client.methods.HttpPut;
011import org.apache.http.impl.client.CloseableHttpClient;
012
013/**
014 * Interface to enable testing service calls with provided responses. For an
015 * example see IdeServiceClientTest.
016 */
017@FunctionalInterface
018public interface ServiceClientCallable<T> {
019
020        /** Overridden by implementors, actually starts the service call */
021        T call(HttpClient client) throws ServiceCallException;
022
023        /**
024         * Helper method for starting a service call using a given
025         * {@link CloseableHttpClient}.
026         */
027        static <T> T withHttpClient(CloseableHttpClient client, ServiceClientCallable<T> callable)
028                        throws ServiceCallException {
029                try (CloseableHttpClient c = client) {
030                        return callable.call(c);
031                } catch (IOException e) {
032                        throw new ServiceCallException("Problem closing HTTP client: " + e.getMessage(), e);
033                }
034        }
035
036        /**
037         * Helper method for starting a service call with the given
038         * {@link ServerDetails}.
039         */
040        static <T> T with(ServerDetails serverDetails, ServiceClientCallable<T> callable) throws ServiceCallException {
041                return withHttpClient(ServiceClientUtils.getHttpClient(serverDetails), callable);
042        }
043
044        /**
045         * @return a {@link ServiceClientCallable} for a HTTP GET on the given URI.
046         */
047        static <R> ServiceClientCallable<R> get(IDeserializationFormat<R> deserializationFormat, String uri) {
048                return client -> {
049                        HttpGet httpGet = new HttpGet(uri);
050                        return ServiceClientUtils.executeRequest(client, httpGet, deserializationFormat.getMimeType().orElse(null),
051                                        deserializationFormat::deserialize);
052                };
053        }
054
055        /**
056         * @return a {@link ServiceClientCallable} for a HTTP POST on the given URI.
057         */
058        static <S, T extends S, R> ServiceClientCallable<R> post(ISerializationFormat<S> serializationFormat, T data,
059                        IDeserializationFormat<R> deserializationFormat, String uri) {
060                return client -> {
061                        HttpPost httpPost = new HttpPost(uri);
062                        serializationFormat.getMimeType()
063                                        .ifPresent(mimeType -> httpPost.setHeader(HttpHeaders.CONTENT_TYPE, mimeType.getType()));
064                        httpPost.setEntity(serializationFormat.toHttpEntity(data));
065                        return ServiceClientUtils.executeRequest(client, httpPost, deserializationFormat.getMimeType().orElse(null),
066                                        deserializationFormat::deserialize);
067                };
068        }
069
070        /**
071         * @return a {@link ServiceClientCallable} for a HTTP POST on the given URI.
072         */
073        static <R> ServiceClientCallable<R> post(IDeserializationFormat<R> deserializationFormat, String uri) {
074                return client -> {
075                        HttpPost httpPost = new HttpPost(uri);
076                        return ServiceClientUtils.executeRequest(client, httpPost, deserializationFormat.getMimeType().orElse(null),
077                                        deserializationFormat::deserialize);
078                };
079        }
080
081        /**
082         * @return a {@link ServiceClientCallable} for a HTTP PUT on the given URI.
083         */
084        static <S, T extends S, R> ServiceClientCallable<R> put(ISerializationFormat<S> serializationFormat, T data,
085                        IDeserializationFormat<R> deserializationFormat, String uri) {
086                return client -> {
087                        HttpPut httpPut = new HttpPut(uri);
088                        serializationFormat.getMimeType()
089                                        .ifPresent(mimeType -> httpPut.setHeader(HttpHeaders.CONTENT_TYPE, mimeType.getType()));
090                        httpPut.setEntity(serializationFormat.toHttpEntity(data));
091                        return ServiceClientUtils.executeRequest(client, httpPut, deserializationFormat.getMimeType().orElse(null),
092                                        deserializationFormat::deserialize);
093                };
094        }
095
096        /**
097         * @return a {@link ServiceClientCallable} for a HTTP PUT on the given URI
098         *         without any payload.
099         * @deprecated PUT requests should always have a body
100         */
101        @Deprecated
102        static <R> ServiceClientCallable<R> put(IDeserializationFormat<R> deserializationFormat, String uri) {
103                return client -> {
104                        HttpPut httpPut = new HttpPut(uri);
105                        return ServiceClientUtils.executeRequest(client, httpPut, deserializationFormat.getMimeType().orElse(null),
106                                        deserializationFormat::deserialize);
107                };
108        }
109
110        /**
111         * @return a {@link ServiceClientCallable} for a HTTP DELETE on the given URI.
112         */
113        static <R> ServiceClientCallable<R> delete(IDeserializationFormat<R> deserializationFormat, String uri) {
114                return client -> {
115                        HttpDelete httpDelete = new HttpDelete(uri);
116                        return ServiceClientUtils.executeRequest(client, httpDelete,
117                                        deserializationFormat.getMimeType().orElse(null), deserializationFormat::deserialize);
118                };
119        }
120}