All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dbflute.remoteapi.mock.MockHttpClient Maven / Gradle / Ivy

/*
 * Copyright 2015-2019 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 org.dbflute.remoteapi.mock;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.protocol.HttpContext;
import org.dbflute.helper.message.ExceptionMessageBuilder;
import org.dbflute.remoteapi.mock.supporter.MockFreedomResponse;
import org.dbflute.remoteapi.mock.supporter.MockFreedomResponse.MockHttpResponseProvider;
import org.dbflute.remoteapi.mock.supporter.MockFreedomResponse.MockHttpResponseResource;
import org.dbflute.remoteapi.mock.supporter.MockFreedomResponse.MockRequestPeeking;
import org.dbflute.remoteapi.mock.supporter.MockSupposedRequest;
import org.dbflute.util.DfResourceUtil;

/**
 * @author awane
 * @author jflute
 */
public class MockHttpClient extends CloseableHttpClient {

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected final MockFreedomResponse freedomResponse;

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    protected MockHttpClient(MockFreedomResponse freedomResponse) {
        this.freedomResponse = freedomResponse;
    }

    // e.g.
    //  MockHttpClient.create(response -> {
    //      response.asJson(path, request -> request...);
    //      response.peekRequest(request -> {});
    //  });
    public static MockHttpClient create(MockFreedomResponseSetupper responseLambda) {
        MockFreedomResponse response = new MockFreedomResponse();
        responseLambda.setup(response);
        return new MockHttpClient(response);
    }

    public static interface MockFreedomResponseSetupper {

        void setup(MockFreedomResponse response);
    }

    // ===================================================================================
    //                                                                             Execute
    //                                                                             =======
    @Override
    protected CloseableHttpResponse doExecute(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext)
            throws IOException, ClientProtocolException {
        final Charset charset = StandardCharsets.UTF_8;
        final String url = extractRequestUrl(httpRequest); // e.g. http://localhost:8090/harbor/lido/product/list/1
        final String body = extractRequestBody(httpRequest, charset); // null allowed
        final Map> headerMap = extractHeaderMap(httpRequest);
        final String hostName = httpHost.getHostName();
        final Integer port = httpHost.getPort() >= 0 ? httpHost.getPort() : null;
        final MockSupposedRequest supposedRequest = new MockSupposedRequest(url, body, hostName, port, headerMap);
        final List requestHandlerList = freedomResponse.getRequestPeekingList();
        for (MockRequestPeeking requestHandler : requestHandlerList) {
            requestHandler.peek(supposedRequest);
        }
        final List responseResourceList = freedomResponse.getResponseResourceList();
        for (MockHttpResponseResource responseResource : responseResourceList) {
            final MockHttpResponseProvider responseProvider = responseResource.getResponseProvider();
            final MockHttpResponse provided = responseProvider.provide(supposedRequest);
            if (provided != null) {
                responseResource.getHttpStatus().ifPresent(httpStatus -> {
                    provided.setStatusCode(httpStatus);
                });
                return provided;
            }
        }
        throwMockHttpResponseNotFoundException(supposedRequest, responseResourceList);
        return null; // unreachable
    }

    protected String extractRequestUrl(HttpRequest request) {
        final Charset charset = StandardCharsets.UTF_8;
        final String url;
        try {
            url = URLDecoder.decode(request.getRequestLine().getUri(), charset.name());
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException("Not found the encoding: " + charset, e);
        }
        return url;
    }

    protected String extractRequestBody(HttpRequest request, Charset charset) {
        final String body;
        if (request instanceof HttpEntityEnclosingRequest) {
            final HttpEntityEnclosingRequest httpPost = (HttpEntityEnclosingRequest) request;
            final HttpEntity entity = httpPost.getEntity();
            if (entity != null) {
                try (InputStream content = entity.getContent(); InputStreamReader reader = new InputStreamReader(content, charset)) {
                    body = DfResourceUtil.readText(reader);
                } catch (UnsupportedOperationException | IOException e) {
                    throw new IllegalStateException("Failed to read the text: request=" + request, e);
                }
            } else { // e.g. POST but noRequestBody()
                body = null;
            }
        } else { // e.g. GET
            body = null;
        }
        return body;
    }

    protected Map> extractHeaderMap(HttpRequest httpRequest) {
        final Header[] allHeaders = httpRequest.getAllHeaders();
        final Map> headerMap = new LinkedHashMap>();
        if (allHeaders != null) { // just in case
            for (Header header : allHeaders) {
                final String name = header.getName();
                List elementList = headerMap.get(name);
                if (elementList == null) {
                    elementList = new ArrayList();
                    headerMap.put(name, elementList);
                }
                elementList.add(header.getValue());
            }
            for (Entry> entry : headerMap.entrySet()) {
                headerMap.put(entry.getKey(), Collections.unmodifiableList(entry.getValue()));
            }
        }
        return Collections.unmodifiableMap(headerMap);
    }

    protected void throwMockHttpResponseNotFoundException(MockSupposedRequest supposedRequest,
            List responseResourceList) {
        final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
        br.addNotice("Not found the mock response for the request.");
        br.addItem("Advice");
        br.addElement("This is how to mock response:");
        br.addElement("  (o):");
        br.addElement("    MockHttpClient client = MockHttpClient.create(resopnse -> {");
        br.addElement("        resopnse.asJson(json, request -> true); // *here");
        br.addElement("    });");
        br.addElement("The asJson()'s second argument is lambda");
        br.addElement("to determine the target request like this:");
        br.addElement("  (o):");
        br.addElement("    MockHttpClient client = MockHttpClient.create(resopnse -> {");
        br.addElement("        resopnse.asJson(json, request -> request.getUrl().contains(\"/harbor/\")); // *here");
        br.addElement("    });");
        br.addElement("So the condition is wrong then not found.");
        br.addElement("Confirm your condition implementation.");
        br.addItem("Requset");
        br.addElement(supposedRequest.getUrl());
        supposedRequest.getBody().ifPresent(supportedBody -> {
            br.addElement(supportedBody);
        });
        br.addItem("Response Resource");
        br.addElement(responseResourceList);
        final String msg = br.buildExceptionMessage();
        throw new IllegalStateException(msg);
    }

    // ===================================================================================
    //                                                              Empty Request Override
    //                                                              ======================
    @SuppressWarnings("deprecation")
    @Override
    public org.apache.http.params.HttpParams getParams() {
        return null;
    }

    @SuppressWarnings("deprecation")
    @Override
    public org.apache.http.conn.ClientConnectionManager getConnectionManager() {
        return null;
    }

    @Override
    public void close() throws IOException {
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy