Skip to content

Backport transport refactor #769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion java-client/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ publishing {
dependencies {
// Compile and test with the last 7.x version to make sure transition scenarios where
// the Java API client coexists with a 7.x HLRC work fine
val elasticsearchVersion = "7.17.7"
val elasticsearchVersion = "7.17.18"
val jacksonVersion = "2.17.0"

// Apache 2.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package co.elastic.clients.elasticsearch._types;

import co.elastic.clients.transport.http.TransportHttpClient;

import javax.annotation.Nullable;

/**
Expand All @@ -33,11 +35,19 @@ public class ElasticsearchException extends RuntimeException {

private final ErrorResponse response;
private final String endpointId;
@Nullable
private final TransportHttpClient.Response httpResponse;

public ElasticsearchException(String endpointId, ErrorResponse response) {
public ElasticsearchException(String endpointId, ErrorResponse response,
@Nullable TransportHttpClient.Response httpResponse) {
super("[" + endpointId + "] failed: [" + response.error().type() + "] " + response.error().reason());
this.response = response;
this.endpointId = endpointId;
this.httpResponse = httpResponse;
}

public ElasticsearchException(String endpointId, ErrorResponse response) {
this(endpointId, response, null);
}

/**
Expand Down Expand Up @@ -68,4 +78,12 @@ public ErrorCause error() {
public int status() {
return this.response.status();
}

/**
* The underlying http response, if available.
*/
@Nullable
public TransportHttpClient.Response httpResponse() {
return this.httpResponse;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 co.elastic.clients.transport;

import co.elastic.clients.transport.http.HeaderMap;
import co.elastic.clients.util.ObjectBuilderBase;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
* Default implementation of {@link TransportOptions}. Extensions can use it as a base class to provide additional features.
*/
public class DefaultTransportOptions implements TransportOptions {
private final HeaderMap headers;
private final Map<String, String> parameters;
private final Function<List<String>, Boolean> onWarnings;

public static final DefaultTransportOptions EMPTY = new DefaultTransportOptions();

public DefaultTransportOptions() {
this(new HeaderMap(), Collections.emptyMap(), null);
}

public DefaultTransportOptions(
@Nullable HeaderMap headers,
@Nullable Map<String, String> parameters,
@Nullable Function<List<String>, Boolean> onWarnings
) {
this.headers = headers == null ? HeaderMap.EMPTY : headers;
this.parameters = (parameters == null || parameters.isEmpty()) ?
Collections.emptyMap() : Collections.unmodifiableMap(parameters);
this.onWarnings = onWarnings;
}

protected DefaultTransportOptions(AbstractBuilder<?> builder) {
this(builder.headers, builder.parameters, builder.onWarnings);
}

public static DefaultTransportOptions of(@Nullable TransportOptions options) {
if (options == null) {
return new DefaultTransportOptions(null, null, null);
}
if (options instanceof DefaultTransportOptions) {
return (DefaultTransportOptions) options;
}
return new DefaultTransportOptions(
new HeaderMap(entriesToMap(options.headers())),
options.queryParameters(),
options.onWarnings()
);
}

@Override
public Collection<Map.Entry<String, String>> headers() {
return Collections.unmodifiableSet(headers.entrySet());
}

@Override
public Map<String, String> queryParameters() {
return parameters;
}

@Override
public Function<List<String>, Boolean> onWarnings() {
return onWarnings;
}

@Override
public Builder toBuilder() {
return new Builder(this);
}

private static <K, V> Map<K, V> entriesToMap(Collection<Map.Entry<K, V>> entries) {
if (entries.isEmpty()) {
return Collections.emptyMap();
} else {
HashMap<K, V> map = new HashMap<>();
for (Map.Entry<K, V> entry: entries) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
}

public abstract static class AbstractBuilder<BuilderT extends AbstractBuilder<BuilderT>>
extends ObjectBuilderBase implements TransportOptions.Builder {

private HeaderMap headers;
private Map<String, String> parameters;
private Function<List<String>, Boolean> onWarnings;

public AbstractBuilder() {
}

public AbstractBuilder(DefaultTransportOptions options) {
this.headers = new HeaderMap(options.headers);
this.parameters = copyOrNull(options.parameters);
this.onWarnings = options.onWarnings;
}

protected abstract BuilderT self();

@Override
public BuilderT addHeader(String name, String value) {
if (name.equalsIgnoreCase(HeaderMap.CLIENT_META)) {
// Not overridable
return self();
}
if (this.headers == null) {
this.headers = new HeaderMap();
}
headers.add(name, value);
return self();
}

@Override
public BuilderT setHeader(String name, String value) {
if (name.equalsIgnoreCase(HeaderMap.CLIENT_META)) {
// Not overridable
return self();
}
if (this.headers == null) {
this.headers = new HeaderMap();
}
headers.put(name, value);
return self();
}

@Override
public BuilderT removeHeader(String name) {
if (this.headers != null) {
headers.remove(name);
}
return self();
}

@Override
public BuilderT setParameter(String name, String value) {
if (parameters == null) {
parameters = new HashMap<>();
}
parameters.put(name, value);
return self();
}

@Override
public BuilderT removeParameter(String name) {
if (parameters != null) {
parameters.remove(name);
};
return self();
}

@Override
public BuilderT onWarnings(Function<List<String>, Boolean> listener) {
this.onWarnings = listener;
return self();
}

private <K, V> Map<K, V> copyOrNull(Map<K, V> map) {
return map.isEmpty() ? null : new HashMap<>(map);
}
}

public static class Builder extends AbstractBuilder<Builder> {

public Builder() {
super();
}

public Builder(DefaultTransportOptions options) {
super(options);
}

@Override
protected Builder self() {
return this;
}

@Override
public TransportOptions build() {
_checkSingleUse();
return new DefaultTransportOptions(this);
}
}
}
Loading