Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpMessage;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.dbflute.helper.function.IndependentProcessor;
import org.dbflute.helper.message.ExceptionMessageBuilder;
import org.dbflute.jdbc.Classification;
import org.dbflute.optional.OptionalThing;
import org.dbflute.remoteapi.exception.RemoteApiErrorTranslationFailureException;
import org.dbflute.remoteapi.exception.RemoteApiFailureResponseTypeNotFoundException;
import org.dbflute.remoteapi.exception.RemoteApiHttpBasisErrorException;
import org.dbflute.remoteapi.exception.RemoteApiHttpBasisErrorException.RemoteApiFailureResponseHolder;
import org.dbflute.remoteapi.exception.RemoteApiHttpClientErrorException;
import org.dbflute.remoteapi.exception.RemoteApiHttpServerErrorException;
import org.dbflute.remoteapi.exception.RemoteApiIOException;
import org.dbflute.remoteapi.exception.RemoteApiPathVariableNullElementException;
import org.dbflute.remoteapi.exception.RemoteApiPathVariableShortElementException;
import org.dbflute.remoteapi.exception.RemoteApiReceiverOfResponseBodyNotFoundException;
import org.dbflute.remoteapi.exception.RemoteApiResponseParseFailureException;
import org.dbflute.remoteapi.exception.RemoteApiRetryReadyFailureException;
import org.dbflute.remoteapi.exception.RemoteApiSenderOfQueryParameterNotFoundException;
import org.dbflute.remoteapi.exception.RemoteApiSenderOfRequestBodyNotFoundException;
import org.dbflute.remoteapi.exception.retry.ClientErrorRetryDeterminer;
import org.dbflute.remoteapi.exception.retry.ClientErrorRetryResource;
import org.dbflute.remoteapi.exception.translation.ClientErrorTranslatingResource;
import org.dbflute.remoteapi.http.EmptyRequestBody;
import org.dbflute.remoteapi.http.HttpDeleteEnclosing;
import org.dbflute.remoteapi.http.SupportedHttpMethod;
import org.dbflute.remoteapi.logging.SendReceiveLogOption;
import org.dbflute.remoteapi.logging.SendReceiveLogger;
import org.dbflute.remoteapi.receiver.ResponseBodyReceiver;
import org.dbflute.remoteapi.sender.body.RequestBodySender;
import org.dbflute.remoteapi.sender.query.QueryParameterSender;
import org.dbflute.system.DBFluteSystem;
import org.dbflute.util.Srl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author jflute
* @author awaawa
* @author inoue
*/
public class FlutyRemoteApi {
// ===================================================================================
// Definition
// ==========
private static final Logger logger = LoggerFactory.getLogger(FlutyRemoteApi.class);
protected static final Object VOID_OBJ = new Object();
// ===================================================================================
// Attribute
// =========
protected final Consumer defaultRuleLambda; // not null
protected final Object facadeExp; // for various purpose, basically debug, not null
// ===================================================================================
// Constructor
// ===========
public FlutyRemoteApi(Consumer defaultRuleLambda, Object facadeExp) {
assertArgumentNotNull("defaultRuleLambda", defaultRuleLambda);
assertArgumentNotNull("facadeExp", facadeExp);
this.defaultRuleLambda = defaultRuleLambda;
this.facadeExp = facadeExp;
}
// ===================================================================================
// Request GET
// ===========
/**
* Request as GET.
* @param The type of response return.
* @param returnType The class type of bean as return (response body), should have default constructor. (NotNull)
* @param urlBase The base part of URL to remote API server. e.g. http://localhost:8090/harbor (NotNull)
* @param actionPath The path to action without path variables, and trailing slash is no difference. e.g. /sea/land (NotNull)
* @param pathVariables The array of URL path variables, e.g. ["hangar", 3]. (NotNull, EmptyAllowed)
* @param param The optional parameter object of query parameters. (NotNull, EmptyAllowed)
* @param ruleLambda The callback for rule of remote API. (NotNull)
* @return The analyzed return of response from the request. (NotNull)
*/
public RETURN requestGet(Type returnType, String urlBase, String actionPath, Object[] pathVariables,
OptionalThing extends Object> param, Consumer ruleLambda) {
return doRequestEmptyBody(returnType, urlBase, actionPath, pathVariables, param, ruleLambda, SupportedHttpMethod.GET, url -> {
return new HttpGet(url);
});
}
// ===================================================================================
// Request POST
// ============
/**
* Request as POST.
* @param The type of response return.(response).
* @param returnType The class type of bean as return (response body), should have default constructor. (NotNull)
* @param urlBase The base part of URL to remote API server. e.g. http://localhost:8090/harbor (NotNull)
* @param actionPath The path to action without path variables, and trailing slash is no difference. e.g. /sea/land (NotNull)
* @param pathVariables The array of URL path variables, e.g. ["hangar", 3]. (NotNull, EmptyAllowed)
* @param param The parameter objet of on-body parameters, may be JSON body. (NotNull)
* @param ruleLambda The callback for rule of remote API. (NotNull)
* @return The analyzed return of response from the request. (NotNull)
*/
public RETURN requestPost(Type returnType, String urlBase, String actionPath, Object[] pathVariables, Object param,
Consumer ruleLambda) {
return doRequestEnclosing(returnType, urlBase, actionPath, pathVariables, param, ruleLambda, SupportedHttpMethod.POST, url -> {
return new HttpPost(url);
});
}
// ===================================================================================
// Request PUT
// ===========
/**
* Request as PUT.
* @param The type of response return.
* @param returnType The class type of bean as return (response body), should have default constructor. (NotNull)
* @param urlBase The base part of URL to remote API server. e.g. http://localhost:8090/harbor (NotNull)
* @param actionPath The path to action without path variables, and trailing slash is no difference. e.g. /sea/land (NotNull)
* @param pathVariables The array of URL path variables, e.g. ["hangar", 3]. (NotNull, EmptyAllowed)
* @param param The parameter object of on-body parameters, may be JSON body. (NotNull)
* @param ruleLambda The callback for rule of remote API. (NotNull)
* @return The analyzed return of response from the request. (NotNull)
*/
public RETURN requestPut(Type returnType, String urlBase, String actionPath, Object[] pathVariables, Object param,
Consumer ruleLambda) {
return doRequestEnclosing(returnType, urlBase, actionPath, pathVariables, param, ruleLambda, SupportedHttpMethod.PUT, url -> {
return new HttpPut(url);
});
}
// ===================================================================================
// Request DELETE
// ==============
/**
* Request as DELETE (with query parameter).
* @param The type of response return.
* @param returnType The class type of bean as return (response body), should have default constructor. (NotNull)
* @param urlBase The base part of URL to remote API server. e.g. http://localhost:8090/harbor (NotNull)
* @param actionPath The path to action without path variables, and trailing slash is no difference. e.g. /sea/land (NotNull)
* @param pathVariables The array of URL path variables, e.g. ["hangar", 3]. (NotNull, EmptyAllowed)
* @param param The optional parameter object of query parameters. (NotNull, EmptyAllowed)
* @param ruleLambda The callback for rule of remote API. (NotNull)
* @return The analyzed return of response from the request. (NotNull)
*/
public RETURN requestDelete(Type returnType, String urlBase, String actionPath, Object[] pathVariables,
OptionalThing extends Object> param, Consumer ruleLambda) {
return doRequestEmptyBody(returnType, urlBase, actionPath, pathVariables, param, ruleLambda, SupportedHttpMethod.DELETE, url -> {
return new HttpDelete(url);
});
}
/**
* Request as DELETE with entity-enclosing.
* @param The type of response return.
* @param returnType The class type of bean as return (response body), should have default constructor. (NotNull)
* @param urlBase The base part of URL to remote API server. e.g. http://localhost:8090/harbor (NotNull)
* @param actionPath The path to action without path variables, and trailing slash is no difference. e.g. /sea/land (NotNull)
* @param pathVariables The array of URL path variables, e.g. ["hangar", 3]. (NotNull, EmptyAllowed)
* @param param The parameter object of on-body parameters, may be JSON body. (NotNull)
* @param ruleLambda The callback for rule of remote API. (NotNull)
* @return The analyzed return of response from the request. (NotNull)
*/
public RETURN requestDeleteEnclosing(Type returnType, String urlBase, String actionPath, Object[] pathVariables, Object param,
Consumer ruleLambda) {
return doRequestEnclosing(returnType, urlBase, actionPath, pathVariables, param, ruleLambda, SupportedHttpMethod.DELETE, url -> {
return new HttpDeleteEnclosing(url);
});
}
// ===================================================================================
// Request PATCH
// =============
/**
* Request as PATCH.
* @param The type of response return.
* @param returnType The class type of bean as return (response body), should have default constructor. (NotNull)
* @param urlBase The base part of URL to remote API server. e.g. http://localhost:8090/harbor (NotNull)
* @param actionPath The path to action without path variables, and trailing slash is no difference. e.g. /sea/land (NotNull)
* @param pathVariables The array of URL path variables, e.g. ["hangar", 3]. (NotNull, EmptyAllowed)
* @param param The parameter object of on-body parameters, may be JSON body. (NotNull)
* @param ruleLambda The callback for rule of remote API. (NotNull)
* @return The analyzed return of response from the request. (NotNull)
*/
public RETURN requestPatch(Type returnType, String urlBase, String actionPath, Object[] pathVariables, Object param,
Consumer ruleLambda) {
return doRequestEnclosing(returnType, urlBase, actionPath, pathVariables, param, ruleLambda, SupportedHttpMethod.PATCH, url -> {
return new HttpPatch(url);
});
}
// ===================================================================================
// Request EmptyBody
// =================
protected RETURN doRequestEmptyBody(Type returnType, String urlBase, String actionPath, Object[] pathVariables,
OptionalThing extends Object> optParam, Consumer ruleLambda, SupportedHttpMethod httpMethod,
Function emptyBodyFactory) {
assertArgumentNotNull("returnType", returnType);
assertArgumentNotNull("urlBase", urlBase);
assertArgumentNotNull("actionPath", actionPath);
assertArgumentNotNull("pathVariables", pathVariables);
assertArgumentNotNull("param", optParam); // variable name is for facade method
assertArgumentNotNull("ruleLambda", ruleLambda);
assertArgumentNotNull("httpMethod", httpMethod);
assertArgumentNotNull("emptyBodyFactory", emptyBodyFactory);
final FlutyRemoteApiRule rule = createRemoteApiRule(ruleLambda);
keepBeginDateTimeIfNeeds(rule);
keepFacadeExpIfNeeds(rule);
return retryableRequest(returnType, urlBase, actionPath, pathVariables, optParam, rule, () -> {
return actuallyRequestEmptyBody(returnType, urlBase, actionPath, pathVariables, optParam, rule, httpMethod, emptyBodyFactory);
}, clientError -> {
return createClientErrorRetryResource(returnType, urlBase, actionPath, pathVariables, optParam, rule, httpMethod, clientError);
});
}
protected RETURN actuallyRequestEmptyBody(Type returnType, String urlBase, String actionPath, Object[] pathVariables,
OptionalThing extends Object> optParam, FlutyRemoteApiRule rule, SupportedHttpMethod httpMethod,
Function emptyBodyFactory) {
optParam.ifPresent(param -> validateParam(returnType, urlBase, actionPath, pathVariables, param, rule));
final String requestPath = buildRequestPath(returnType, urlBase, actionPath, pathVariables, optParam, rule);
final String url = buildUrl(returnType, urlBase, requestPath, optParam, rule);
showBeginEmptyBody(rule, httpMethod, url);
return delegateExecute(httpMethod, requestPath, rule, () -> {
return executeEmptyBody(returnType, url, rule, httpMethod, emptyBodyFactory);
});
}
protected void showBeginEmptyBody(FlutyRemoteApiRule rule, SupportedHttpMethod httpMethod, final String url) {
if (!logger.isDebugEnabled()) {
return;
}
final Map> headerMap = rule.getHeaders().orElseGet(() -> Collections.emptyMap());
logger.debug("#flow #remote ...Sending request as {} to Remote API:\n{}\n with headers: {}", httpMethod, url, headerMap);
}
protected RETURN executeEmptyBody(Type returnType, String url, FlutyRemoteApiRule rule, SupportedHttpMethod httpMethod,
Function emptyBodyFactory) {
try (CloseableHttpClient httpClient = buildHttpClient(rule)) {
final HttpUriRequest httpEmptyBody = prepareHttpEmptyBody(url, rule, httpMethod, emptyBodyFactory);
try (CloseableHttpResponse response = httpClient.execute(httpEmptyBody)) {
return handleResponse(returnType, url, /*param*/OptionalThing.empty(), response, rule);
}
} catch (IOException e) {
handleRemoteApiIOException(returnType, url, /*param*/OptionalThing.empty(), e);
return null; // unreachable
}
}
protected HttpUriRequest prepareHttpEmptyBody(String url, FlutyRemoteApiRule rule, SupportedHttpMethod httpMethod,
Function emptyBodyFactory) {
final HttpUriRequest httpEmptyBody = emptyBodyFactory.apply(url);
setupHeader(httpEmptyBody, rule);
return httpEmptyBody;
}
// ===================================================================================
// Request Enclosing
// =================
protected RETURN doRequestEnclosing(Type returnType, String urlBase, String actionPath, Object[] pathVariables, Object param,
Consumer ruleLambda, SupportedHttpMethod httpMethod,
Function enclosingFactory) {
assertArgumentNotNull("returnType", returnType);
assertArgumentNotNull("urlBase", urlBase);
assertArgumentNotNull("actionPath", actionPath);
assertArgumentNotNull("pathVariables", pathVariables);
assertArgumentNotNull("param", param);
assertArgumentNotNull("ruleLambda", ruleLambda);
assertArgumentNotNull("httpMethod", httpMethod);
assertArgumentNotNull("enclosingFactory", enclosingFactory);
final FlutyRemoteApiRule rule = createRemoteApiRule(ruleLambda);
keepBeginDateTimeIfNeeds(rule);
keepFacadeExpIfNeeds(rule);
return retryableRequest(returnType, urlBase, actionPath, pathVariables, param, rule, () -> {
return actuallyRequestEnclosing(returnType, urlBase, actionPath, pathVariables, param, rule, httpMethod, enclosingFactory);
}, clientError -> {
final OptionalThing