Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
36 changes: 1 addition & 35 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>github-client</artifactId>
<version>0.3.12-SNAPSHOT</version>
<version>0.4.0-SNAPSHOT</version>

<parent>
<groupId>com.spotify</groupId>
Expand Down Expand Up @@ -86,8 +86,6 @@
<opencensus.version>0.31.1</opencensus.version>
<okhttp.version>4.11.0</okhttp.version>
<opentelemetry.version>1.42.1</opentelemetry.version>

<shade.id>${project.groupId}.githubclient.shade</shade.id>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -474,38 +472,6 @@
</sourceDirectories>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>${project.groupId}:${project.artifactId}</include>
<include>com.squareup.okhttp3</include>
<include>com.squareup.okio</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>okhttp3</pattern>
<shadedPattern>${shade.id}.okhttp3</shadedPattern>
</relocation>
<relocation>
<pattern>okio</pattern>
<shadedPattern>${shade.id}.okio</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/com/spotify/github/http/HttpClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*-
* -\-\-
* github-api
* --
* Copyright (C) 2021 Spotify AB
* --
* 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.spotify.github.http;

import com.spotify.github.tracing.Tracer;
import java.util.concurrent.CompletableFuture;

public interface HttpClient {
CompletableFuture<HttpResponse> send(HttpRequest request);
void setTracer(Tracer tracer);
}
43 changes: 43 additions & 0 deletions src/main/java/com/spotify/github/http/HttpRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*-
* -\-\-
* github-api
* --
* Copyright (C) 2021 Spotify AB
* --
* 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.spotify.github.http;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.spotify.github.GithubStyle;
import org.immutables.value.Value;

import java.util.List;
import java.util.Map;

@Value.Immutable
@GithubStyle
@JsonSerialize(as = ImmutableHttpRequest.class)
@JsonDeserialize(as = ImmutableHttpRequest.class)
public interface HttpRequest {
String method();

String url();

String body();

Map<String, List<String>> headers();
}
36 changes: 36 additions & 0 deletions src/main/java/com/spotify/github/http/HttpResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*-
* -\-\-
* github-api
* --
* Copyright (C) 2021 Spotify AB
* --
* 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.spotify.github.http;

import java.io.InputStream;
import java.util.List;
import java.util.Map;

public interface HttpResponse {
HttpRequest request();
int statusCode();
String statusMessage();
InputStream body();
String bodyString();
Map<String, List<String>> headers();
boolean isSuccessful();
void close();
}
191 changes: 191 additions & 0 deletions src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/*-
* -\-\-
* github-api
* --
* Copyright (C) 2021 Spotify AB
* --
* 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.spotify.github.http.okhttp;

import static okhttp3.MediaType.parse;

import com.spotify.github.http.HttpClient;
import com.spotify.github.http.HttpRequest;
import com.spotify.github.http.HttpResponse;
import com.spotify.github.http.ImmutableHttpRequest;
import com.spotify.github.tracing.NoopTracer;
import com.spotify.github.tracing.Span;
import com.spotify.github.tracing.TraceHelper;
import com.spotify.github.tracing.Tracer;
import com.spotify.github.tracing.opencensus.OpenCensusTracer;
import com.spotify.github.tracing.opentelemetry.OpenTelemetryTracer;
import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetry;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;

public class OkHttpHttpClient implements HttpClient {
private final OkHttpClient client;
private Tracer tracer;
private Call.Factory callFactory;

public OkHttpHttpClient(final OkHttpClient client) {
this.client = client;
this.tracer = NoopTracer.INSTANCE;
this.callFactory = createTracedClient();
}

public OkHttpHttpClient(final OkHttpClient client, final Tracer tracer) {
this.client = client;
this.tracer = tracer;
this.callFactory = createTracedClient();
}

Check warning on line 57 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L53-L57

Added lines #L53 - L57 were not covered by tests

@Override
public CompletableFuture<HttpResponse> send(final HttpRequest httpRequest) {
Request request = buildRequest(httpRequest);
CompletableFuture<HttpResponse> future = new CompletableFuture<>();
try (Span span = tracer.span(httpRequest)) {
if (this.callFactory == null) {
this.callFactory = createTracedClient();

Check warning on line 65 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L65

Added line #L65 was not covered by tests
}
this.callFactory
.newCall(request)
.enqueue(
new Callback() {

@Override
public void onResponse(@NotNull final Call call, @NotNull final Response response)
throws IOException {
future.complete(new OkHttpHttpResponse(httpRequest, response));
}

@Override
public void onFailure(@NotNull final Call call, @NotNull final IOException e) {
future.completeExceptionally(e);
}

Check warning on line 81 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L80-L81

Added lines #L80 - L81 were not covered by tests
});
tracer.attachSpanToFuture(span, future);
}
return future;
}

@Override
public void setTracer(final Tracer tracer) {
this.tracer = tracer;
this.callFactory = createTracedClient();
}

private Request buildRequest(final HttpRequest request) {
Request.Builder requestBuilder = new Request.Builder().url(request.url());
request
.headers()
.forEach(
(key, values) -> {
values.forEach(value -> requestBuilder.addHeader(key, value));
});
if (request.method().equals("GET")) {
requestBuilder.get();
} else {
requestBuilder.method(
request.method(),
RequestBody.create(parse(javax.ws.rs.core.MediaType.APPLICATION_JSON), request.body()));
}
return requestBuilder.build();
}

private HttpRequest buildHttpRequest(final Request request) {
return ImmutableHttpRequest.builder()
.url(request.url().toString())
.method(request.method())
.headers(request.headers().toMultimap())
.body(Optional.ofNullable(request.body()).map(RequestBody::toString).orElse(""))
.build();

Check warning on line 118 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L113-L118

Added lines #L113 - L118 were not covered by tests
}

private Call.Factory createTracedClient() {
if (this.tracer == null || this.tracer instanceof NoopTracer) {
return createTracedClientNoopTracer();
}
if (this.tracer instanceof OpenCensusTracer) {
return createTracedClientOpenCensus();

Check warning on line 126 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L126

Added line #L126 was not covered by tests
}
if (this.tracer instanceof OpenTelemetryTracer) {
return createTracedClientOpenTelemetry();

Check warning on line 129 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L129

Added line #L129 was not covered by tests
}
return createTracedClientNoopTracer();
}

private Call.Factory createTracedClientNoopTracer() {
return new Call.Factory() {
@NotNull
@Override
public Call newCall(@NotNull final Request request) {
return client.newCall(request);
}
};
}

private Call.Factory createTracedClientOpenTelemetry() {
return OkHttpTelemetry.builder(((OpenTelemetryTracer) this.tracer).getOpenTelemetry())
.build()
.newCallFactory(client);

Check warning on line 147 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L145-L147

Added lines #L145 - L147 were not covered by tests
}

private Call.Factory createTracedClientOpenCensus() {
return new Call.Factory() {

Check warning on line 151 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L151

Added line #L151 was not covered by tests
@NotNull
@Override
public Call newCall(@NotNull final Request request) {
CompletableFuture<Response> future = new CompletableFuture<>();
Span span =

Check warning on line 156 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L155-L156

Added lines #L155 - L156 were not covered by tests
OkHttpHttpClient.this
.tracer
.span(buildHttpRequest(request))
.addTag(TraceHelper.TraceTags.HTTP_URL, request.url().toString());
OkHttpClient.Builder okBuilder = client.newBuilder();
okBuilder
.networkInterceptors()
.add(

Check warning on line 164 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L159-L164

Added lines #L159 - L164 were not covered by tests
0,
new Interceptor() {

Check warning on line 166 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L166

Added line #L166 was not covered by tests
@NotNull
@Override
public Response intercept(@NotNull final Chain chain) throws IOException {
try {
Response response = chain.proceed(chain.request());
span.addTag(TraceHelper.TraceTags.HTTP_STATUS_CODE, response.code())
.addTag(TraceHelper.TraceTags.HTTP_STATUS_MESSAGE, response.message())
.success();
future.complete(response);
return response;
} catch (Exception ex) {
span.failure(ex);
future.completeExceptionally(ex);
throw ex;

Check warning on line 180 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L171-L180

Added lines #L171 - L180 were not covered by tests
} finally {
span.close();

Check warning on line 182 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L182

Added line #L182 was not covered by tests
}
}
});

return okBuilder.build().newCall(request);

Check warning on line 187 in src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java#L187

Added line #L187 was not covered by tests
}
};
}
}
Loading