com.jsunsoft.http.BasicResponseHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of http-request Show documentation
Show all versions of http-request Show documentation
Enhancing apache http client
/*
* Copyright (c) 2017-2021. Benik Arakelyan
*
* 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 com.jsunsoft.http;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.message.HeaderGroup;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* ResponseHandler objects are immutable they can be shared.
*
* @param Type of deserialized content from response
*/
final class BasicResponseHandler implements ResponseHandler {
private final int statusCode;
private final T content;
private final HeaderGroup headerGroup;
private final String errorText;
private final boolean isVoidType;
private final ContentType contentType;
private final URI uri;
private final boolean success;
private final ConnectionFailureType connectionFailureType;
BasicResponseHandler(T content, int statusCode, String errorText, Type type, ContentType contentType, URI uri, ConnectionFailureType connectionFailureType) {
this(content, statusCode, new HeaderGroup(), errorText, type, contentType, uri, connectionFailureType);
}
BasicResponseHandler(T content, int statusCode, HeaderGroup headerGroup, String errorText, Type type, ContentType contentType, URI uri) {
this(content, statusCode, headerGroup, errorText, type, contentType, uri, BasicConnectionFailureType.NONE);
}
private BasicResponseHandler(T content, int statusCode, HeaderGroup headerGroup, String errorText, Type type, ContentType contentType, URI uri, ConnectionFailureType connectionFailureType) {
this.statusCode = statusCode;
this.content = content;
this.headerGroup = headerGroup;
this.errorText = errorText;
this.isVoidType = HttpRequestUtils.isVoidType(type);
this.contentType = contentType;
this.uri = ArgsCheck.notNull(uri, "uri");
this.success = HttpRequestUtils.isSuccess(statusCode);
this.connectionFailureType = ArgsCheck.notNull(connectionFailureType, "connectionFailureType");
}
/**
* @return {@code true} If content is present else {@code false}
*/
@Override
public boolean hasContent() {
return content != null;
}
/**
* @return {@code true} If hasn't content else {@code false}
*/
@Override
public boolean hasNotContent() {
return content == null;
}
@Override
public int getCode() {
return statusCode;
}
/**
* @param defaultValue value to return if content isn't present
* @return Deserialized Content from response. If content isn't present returns defaultValue.
* @throws UnsupportedOperationException if generic type is a Void
*/
@Override
public T orElse(T defaultValue) {
check();
return content == null ? defaultValue : content;
}
/**
* @param defaultValue value to return if status code is success and hasn't body
* @return Deserialized Content from response. If hasn't body returns defaultValue.
* @throws UnexpectedStatusCodeException If status code is not success
* @throws UnsupportedOperationException if generic type is a Void
*/
@Override
public T orElseThrow(T defaultValue) {
check();
if (isNonSuccess()) {
throw new UnexpectedStatusCodeException(statusCode, errorText, uri);
}
return content == null ? defaultValue : content;
}
/**
* @param exceptionFunction Instance of type {@link Function} by parameter this which returns exception to throw if status code isn't success.
* @param Type of the exception to be thrown
* @return Deserialized content from response. If hasn't body returns {@code null}.
* @throws X If status code isn't success.
*/
@Override
public T orThrow(Function, X> exceptionFunction) throws X {
check();
if (isNonSuccess()) {
throw exceptionFunction.apply(this);
}
return content;
}
/**
* @param defaultValue Value to return if content is {@code null}
* @param exceptionFunction Instance of type {@link Function} by parameter this which returns exception to throw if status code isn't success.
* @param Type of the exception to be thrown
* @return Deserialized content from response. If hasn't body returns {@code defaultValue}.
* @throws X If status code isn't success.
*/
@Override
public T orThrow(T defaultValue, Function, X> exceptionFunction) throws X {
check();
if (isNonSuccess()) {
throw exceptionFunction.apply(this);
}
return content == null ? defaultValue : content;
}
/**
* @param exceptionSupplier Instance of type {@link Supplier} which returns exception to throw if status code isn't success.
* @param Type of the exception to be thrown
* @return Deserialized content from response. If hasn't body returns {@code null}.
* @throws X If status code isn't success.
*/
@Override
public T getOrThrow(Supplier exceptionSupplier) throws X {
check();
if (isNonSuccess()) {
throw exceptionSupplier.get();
}
return content;
}
/**
* @param defaultValue Value to return if content is {@code null}
* @param exceptionSupplier Instance of type {@link Supplier} which returns exception to throw if status code isn't success.
* @param Type of the exception to be thrown
* @return Deserialized content from response. If hasn't body returns {@code defaultValue}.
* @throws X If status code isn't success.
*/
@Override
public T getOrThrow(T defaultValue, Supplier exceptionSupplier) throws X {
check();
if (isNonSuccess()) {
throw exceptionSupplier.get();
}
return content == null ? defaultValue : content;
}
/**
* @return Content from response. Returns null if hasn't body
* @throws UnexpectedStatusCodeException If response code is not success
* @throws UnsupportedOperationException if generic type is a Void
*/
@Override
public T orElseThrow() {
check();
if (isSuccess()) {
return content;
}
throw new UnexpectedStatusCodeException(statusCode, errorText, uri);
}
/**
* Strongly recommend call get method after check content is present.
* For example
*
* if(responseHandler.hasContent()){
* responseHandler.get()
* }
*
*
* @return Deserialized content from response.
* @throws NoSuchContentException If content is not present
* @throws UnsupportedOperationException if generic type is a Void
* @see BasicResponseHandler#orElse(Object)
* @see BasicResponseHandler#ifHasContent(Consumer)
*/
@Override
public T get() {
check();
if (content == null) {
throw new NoSuchContentException("Content is not present: Response code: [" + statusCode + ']');
}
return content;
}
@Override
public T requiredGet() {
check();
if (isSuccess()) {
if (hasContent()) {
return content;
} else {
throw new MissingResponseBodyException(statusCode, uri);
}
} else {
throw new UnexpectedStatusCodeException(statusCode, errorText, uri);
}
}
@Override
public Optional getAsOptional() {
check();
return Optional.ofNullable(content);
}
@Override
public Optional getAsOptionalOrThrow() {
check();
if (isSuccess()) {
return Optional.ofNullable(content);
}
throw new UnexpectedStatusCodeException(statusCode, errorText, uri);
}
/**
* @return Returns the error text if the connection failed but the server sent useful data nonetheless.
* @throws NoSuchElementException If error text is not present
* @throws UnsupportedOperationException if generic type is a Void
*/
@Override
public String getErrorText() {
if (errorText == null) {
throw new IllegalStateException("Error text is not available: Response code: [" + statusCode + ']');
}
return errorText;
}
/**
* @return Returns the connection URI
*/
@Override
public URI getURI() {
return uri;
}
/**
* @return Content type of response
*/
@Override
public ContentType getContentType() {
return contentType;
}
/**
* @return Returns true if status code contains [200, 300) else false
*/
@Override
public boolean isSuccess() {
return success;
}
/**
* @return Returns true if status code isn't contains [200, 300) else false
*/
@Override
public boolean isNonSuccess() {
return !isSuccess();
}
/**
* If has a content, invoke the specified consumer with the content, otherwise do nothing.
*
* @param consumer block to be executed if has a content
* @throws IllegalArgumentException if {@code consumer} is null
*/
@Override
public void ifHasContent(Consumer super T> consumer) {
ArgsCheck.notNull(consumer, "consumer");
if (content != null) {
consumer.accept(content);
}
}
/**
* If status code is success , invoke the specified consumer with the responseHandler and returns {@code OtherwiseSupport} with ignore else {@code OtherwiseSupport} with not ignore.
*
* @param consumer block to be executed if status code is success.
* @return OtherwiseSupport instance to support action otherwise.
* @see OtherwiseSupport#otherwise(Consumer)
*/
@Override
public OtherwiseSupport ifSuccess(Consumer> consumer) {
ArgsCheck.notNull(consumer, "consumer");
OtherwiseSupport otherwiseSupportResult;
if (success) {
consumer.accept(this);
otherwiseSupportResult = OtherwiseSupport.createIgnored(this);
} else {
otherwiseSupportResult = OtherwiseSupport.createNotIgnored(this);
}
return otherwiseSupportResult;
}
/**
* If status code is success , invoke the specified consumer with the responseHandler.
*
* @param consumer block to be executed if status code is not success.
*/
@Override
public void ifNotSuccess(Consumer> consumer) {
ArgsCheck.notNull(consumer, "consumer");
if (!success) {
consumer.accept(this);
}
}
@Override
public FilterSupport filter(Predicate> predicate) {
return FilterSupport.create(this, predicate);
}
@Override
public boolean containsHeader(String name) {
return headerGroup.containsHeader(name);
}
@Override
public Header[] getHeaders(String name) {
return headerGroup.getHeaders(name);
}
@Override
public Header getFirstHeader(String name) {
return headerGroup.getFirstHeader(name);
}
@Override
public Header getLastHeader(String name) {
return headerGroup.getLastHeader(name);
}
@Override
public Header[] getHeaders() {
return headerGroup.getHeaders();
}
/**
* @return connectionFailureType.
* @see ConnectionFailureType
*/
//todo rename and make public
ConnectionFailureType getConnectionFailureType() {
return connectionFailureType;
}
@Override
public String toString() {
return "ResponseHandler{" +
"statusCode=" + statusCode +
", content=" + content +
", errorText='" + errorText + '\'' +
", uri=" + uri +
", connectionFailureType=" + connectionFailureType +
'}';
}
private void check() {
if (isVoidType) {
throw new UnsupportedOperationException("Content is not available. Generic type is a Void");
}
}
}