Skip to content

Commit

Permalink
Migrate some logic from generated code into the runtime library (#475)
Browse files Browse the repository at this point in the history
Migrate some logic from generated code into the runtime library
  • Loading branch information
carterkozak committed Mar 3, 2020
1 parent 7e647a2 commit 1fad96e
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 28 deletions.
15 changes: 15 additions & 0 deletions .palantir/revapi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
versionOverrides: {}
acceptedBreaks:
"0.12.1":
com.palantir.dialogue:dialogue-apache-hc4-client: []
com.palantir.dialogue:dialogue-blocking-channels: []
com.palantir.dialogue:dialogue-core: []
com.palantir.dialogue:dialogue-httpurlconnection-client: []
com.palantir.dialogue:dialogue-java-client: []
com.palantir.dialogue:dialogue-okhttp-client: []
com.palantir.dialogue:dialogue-serde: []
com.palantir.dialogue:dialogue-target:
- code: "java.method.addedToInterface"
old: null
new: "method com.palantir.dialogue.Clients com.palantir.dialogue.ConjureRuntime::clients()"
justification: "alpha software, runtime not meant for extension"
5 changes: 5 additions & 0 deletions changelog/@unreleased/pr-475.v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type: improvement
improvement:
description: Migrate some logic from generated code into the runtime library
links:
- https://github.com/palantir/dialogue/pull/475
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,15 @@

package com.palantir.dialogue.example;

import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.palantir.dialogue.Channel;
import com.palantir.dialogue.ConjureRuntime;
import com.palantir.dialogue.Deserializer;
import com.palantir.dialogue.Endpoint;
import com.palantir.dialogue.HttpMethod;
import com.palantir.dialogue.PathTemplate;
import com.palantir.dialogue.PlainSerDe;
import com.palantir.dialogue.RemoteExceptions;
import com.palantir.dialogue.Request;
import com.palantir.dialogue.Response;
import com.palantir.dialogue.Serializer;
import com.palantir.dialogue.TypeMarker;
import com.palantir.dialogue.UrlBuilder;
Expand Down Expand Up @@ -138,25 +134,15 @@ public SampleObject objectToObject(
.putAllQueryParams("queryKey", plainSerDe.serializeRidList(query))
.body(sampleObjectToSampleObjectSerializer.serialize(body))
.build();

ListenableFuture<Response> call = channel.execute(STRING_TO_STRING, request);
ListenableFuture<SampleObject> response = Futures.transform(
call,
r -> sampleObjectToSampleObjectDeserializer.deserialize(r),
MoreExecutors.directExecutor());

return RemoteExceptions.getUnchecked(response);
return runtime.clients()
.block(runtime.clients()
.call(channel, STRING_TO_STRING, request, sampleObjectToSampleObjectDeserializer));
}

@Override
public void voidToVoid() {
Request request = Request.builder().build();

ListenableFuture<Response> call = channel.execute(VOID_TO_VOID, request);
ListenableFuture<Void> response = Futures.transform(
call, r -> voidToVoidDeserializer.deserialize(r), MoreExecutors.directExecutor());

RemoteExceptions.getUnchecked(response);
runtime.clients().block(runtime.clients().call(channel, VOID_TO_VOID, request, voidToVoidDeserializer));
}
};
}
Expand Down Expand Up @@ -188,21 +174,14 @@ public ListenableFuture<SampleObject> stringToString(
.putAllQueryParams("queryKey", plainSerDe.serializeRidList(query))
.body(sampleObjectToSampleObjectSerializer.serialize(body))
.build();

ListenableFuture<Response> call = channel.execute(STRING_TO_STRING, request);
return Futures.transform(
call,
response -> sampleObjectToSampleObjectDeserializer.deserialize(response),
MoreExecutors.directExecutor());
return runtime.clients()
.call(channel, STRING_TO_STRING, request, sampleObjectToSampleObjectDeserializer);
}

@Override
public ListenableFuture<Void> voidToVoid() {
Request request = Request.builder().build();

ListenableFuture<Response> call = channel.execute(VOID_TO_VOID, request);
return Futures.transform(
call, response -> voidToVoidDeserializer.deserialize(response), MoreExecutors.directExecutor());
return runtime.clients().call(channel, VOID_TO_VOID, request, voidToVoidDeserializer);
}
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* (c) Copyright 2020 Palantir Technologies Inc. All rights reserved.
*
* 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.palantir.conjure.java.dialogue.serde;

import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.palantir.dialogue.Channel;
import com.palantir.dialogue.Clients;
import com.palantir.dialogue.Deserializer;
import com.palantir.dialogue.Endpoint;
import com.palantir.dialogue.RemoteExceptions;
import com.palantir.dialogue.Request;

/** Package private internal API. */
enum DefaultClients implements Clients {
INSTANCE;

@Override
public <T> ListenableFuture<T> call(
Channel channel, Endpoint endpoint, Request request, Deserializer<T> deserializer) {
return Futures.transform(
channel.execute(endpoint, request), deserializer::deserialize, MoreExecutors.directExecutor());
}

@Override
public <T> T block(ListenableFuture<T> future) {
// TODO(ckozak): remove RemoteExceptions from the codegen target module.
return RemoteExceptions.getUnchecked(future);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.palantir.dialogue.BodySerDe;
import com.palantir.dialogue.Clients;
import com.palantir.dialogue.ConjureRuntime;
import com.palantir.dialogue.PlainSerDe;
import com.palantir.logsafe.Preconditions;
Expand Down Expand Up @@ -52,6 +53,11 @@ public PlainSerDe plainSerDe() {
return ConjurePlainSerDe.INSTANCE;
}

@Override
public Clients clients() {
return DefaultClients.INSTANCE;
}

public static final class Builder {

private final List<Encoding> encodings = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* (c) Copyright 2020 Palantir Technologies Inc. All rights reserved.
*
* 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.palantir.conjure.java.dialogue.serde;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.palantir.dialogue.Channel;
import com.palantir.dialogue.Deserializer;
import com.palantir.dialogue.Endpoint;
import com.palantir.dialogue.Request;
import com.palantir.dialogue.Response;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public final class DefaultClientsTest {

@Mock
private Channel channel;

@Mock
private Endpoint endpoint;

@Mock
private Response response;

@Mock
private Deserializer<String> deserializer;

@Test
public void testCall() throws ExecutionException, InterruptedException {
Request request = Request.builder().build();
when(deserializer.deserialize(eq(response))).thenReturn("value");
SettableFuture<Response> responseFuture = SettableFuture.create();
when(channel.execute(eq(endpoint), eq(request))).thenReturn(responseFuture);
ListenableFuture<String> result = DefaultClients.INSTANCE.call(channel, endpoint, request, deserializer);
assertThat(result).isNotDone();
responseFuture.set(response);
assertThat(result).isDone();
assertThat(result.get()).isEqualTo("value");
}
}
38 changes: 38 additions & 0 deletions dialogue-target/src/main/java/com/palantir/dialogue/Clients.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* (c) Copyright 2020 Palantir Technologies Inc. All rights reserved.
*
* 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.palantir.dialogue;

import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.Future;

/**
* Provides functionality for generated code to make both blocking and asynchronous calls without
* duplicating logic.
*/
public interface Clients {

/**
* Makes a request to the specified {@link Endpoint} and deserializes the response using a provided deserializer.
*/
<T> ListenableFuture<T> call(Channel channel, Endpoint endpoint, Request request, Deserializer<T> deserializer);

/**
* Similar to {@link com.google.common.util.concurrent.Futures#getUnchecked(Future)}, except with custom handling
* for conjure exceptions and cancellation on interruption.
*/
<T> T block(ListenableFuture<T> future);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@ public interface ConjureRuntime {

/** Provides the {@link PlainSerDe} used to parse request path, query, and header parameters. */
PlainSerDe plainSerDe();

/** Provides the {@link Clients} used to facilitate making requests. */
Clients clients();
}

0 comments on commit 1fad96e

Please sign in to comment.