Skip to content

Commit

Permalink
Begin generating client implementations (opensearch-project#1052)
Browse files Browse the repository at this point in the history
* Tweak client generation to extend from existing classes

Signed-off-by: Thomas Farr <[email protected]>

* Modify existing client classes to be abstract base classes

Signed-off-by: Thomas Farr <[email protected]>

* Re-run generator

Signed-off-by: Thomas Farr <[email protected]>

* ./gradlew spotlessApply

Signed-off-by: Thomas Farr <[email protected]>

---------

Signed-off-by: Thomas Farr <[email protected]>
(cherry picked from commit dbde609)
  • Loading branch information
Xtansia committed Aug 30, 2024
1 parent 3111457 commit 7f0adb6
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
Expand Down Expand Up @@ -75,40 +76,83 @@ public void render(ShapeRenderingContext ctx) throws RenderException {
shape.render(ctx);
}

var operations = getOperationsForClient();

if (operations.isEmpty()) return;

// TODO: Render clients when won't be partial and conflict with non-generated code
// new Client(this, false).render(outputDir, formatter);
// new Client(this, true).render(outputDir, formatter);
new Client(this, false, operations).render(ctx);
new Client(this, true, operations).render(ctx);
}

private Collection<RequestShape> getOperationsForClient() {
if ("core".equals(name)) return Collections.emptyList();
return ("".equals(name) ? child("core") : this).operations.values();
}

private String getClientClassName(boolean async, boolean base) {
return "OpenSearch" + Strings.toPascalCase(name) + (async ? "Async" : "") + "Client" + (base ? "Base" : "");
}

private Type getClientType(boolean async, boolean base) {
var type = Type.builder().pkg(getPackageName()).name(getClientClassName(async, base));
if (base) {
type.genericArgs(getClientType(async, false));
}
return type.build();
}

private static class Client extends Shape {
private final boolean async;
private final Collection<RequestShape> operations;

private Client(Namespace parent, boolean async) {
super(parent, "OpenSearch" + Strings.toPascalCase(parent.name) + (async ? "Async" : "") + "Client", null, null);
private Client(Namespace parent, boolean async, Collection<RequestShape> operations) {
super(parent, parent.getClientClassName(async, false), null, null);
this.async = async;
this.operations = operations;
}

@Override
public Type getExtendsType() {
return Types.Client.ApiClient(Types.Client.Transport.OpenSearchTransport, getType());
switch (parent.name) {
case "":
return parent.getClientType(async, true);
default:
return Types.Client.ApiClient(Types.Client.Transport.OpenSearchTransport, getType());
}
}

public String getName() {
return parent.name;
}

public Collection<Client> getChildren() {
return Lists.filterMap(parent.children.values(), n -> !n.operations.isEmpty(), n -> new Client(n, async));
public Collection<ClientRef> getChildren() {
return Lists.filterMap(parent.children.values(), n -> !n.getOperationsForClient().isEmpty(), n -> new ClientRef(n, async));
}

public Collection<RequestShape> getOperations() {
return parent.operations.values();
return operations;
}

public boolean isAsync() {
return this.async;
}

private static class ClientRef {
private final Type type;
private final String name;

public ClientRef(Namespace namespace, boolean async) {
this.type = namespace.getClientType(async, false);
this.name = namespace.name;
}

public Type getType() {
return type;
}

public String getName() {
return name;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public static OperationGroup from(@Nonnull String operationGroup) {
return new OperationGroup(operationGroup.substring(0, index), operationGroup.substring(index + 1));
}

private OperationGroup(@Nullable String namespace, @Nonnull String name) {
public OperationGroup(@Nullable String namespace, @Nonnull String name) {
this.namespace = namespace;
this.name = Strings.requireNonBlank(name, "name must not be blank");
}
Expand All @@ -51,6 +51,11 @@ public String getName() {
return name;
}

@Nonnull
public String asTypedefPrefix() {
return (namespace == null ? "_global" : namespace) + "." + name;
}

@Override
public String toString() {
return namespace == null ? name : namespace + "." + name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class RequestShape extends ObjectShape {
private final Map<String, Field> fields = new TreeMap<>();

public RequestShape(@Nonnull Namespace parent, @Nonnull OperationGroup operationGroup, @Nullable String description) {
super(parent, requestClassName(operationGroup), operationGroup + ".Request", description);
super(parent, requestClassName(operationGroup), operationGroup.asTypedefPrefix() + ".Request", description);
this.operationGroup = operationGroup;
}

Expand Down Expand Up @@ -72,8 +72,8 @@ public void addSupportedHttpMethod(String method) {
httpMethods.add(method);
}

public String getResponseType() {
return responseClassName(operationGroup);
public Type getResponseType() {
return Type.builder().pkg(getPackageName()).name(responseClassName(operationGroup)).build();
}

public boolean canBeSingleton() {
Expand Down Expand Up @@ -145,13 +145,13 @@ public boolean hasAnyRequiredFields() {
}

@Nonnull
public static String requestClassName(@Nonnull OperationGroup operationGroup) {
private static String requestClassName(@Nonnull OperationGroup operationGroup) {
Objects.requireNonNull(operationGroup, "operationGroup must not be null");
return Strings.toPascalCase(operationGroup.getName()) + "Request";
}

@Nonnull
public static String responseClassName(@Nonnull OperationGroup operationGroup) {
private static String responseClassName(@Nonnull OperationGroup operationGroup) {
Objects.requireNonNull(operationGroup, "operationGroup must not be null");
return Strings.toPascalCase(operationGroup.getName()) + "Response";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private void visit(@Nonnull OperationGroup group, @Nonnull List<OpenApiOperation
.map(OpenApiSchema::resolve)
.orElse(OpenApiSchema.ANONYMOUS_OBJECT);

visit(parent, requestShape.getResponseType(), group + ".Response", responseSchema);
visit(parent, requestShape.getResponseType().getName(), group + ".Response", responseSchema);
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ public String toString() {
return str;
}

public String getName() {
return name;
}

public Type getBoxed() {
switch (name) {
case "char":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
return new {{className}}(this.transport, transportOptions);
}
{{#children}}
{{#-first}}

// ----- Child clients
{{/-first}}

public {{type}} {{#camelCase}}{{name}}{{/camelCase}}() {
return new {{type}}(this.transport, this.transportOptions);
Expand All @@ -21,11 +25,23 @@

// ----- Endpoint: {{operationGroup}}

{{#canBeSingleton}}
/**
* {{description}}
*/
public {{#async}}{{TYPES.Java.Util.Concurrent.CompletableFuture}}<{{/async}}{{responseType}}{{#async}}>{{/async}} {{#camelCase}}{{id}}{{/camelCase}}() throws {{TYPES.Java.Io.IOException}}, {{TYPES.Client.OpenSearch._Types.OpenSearchException}} {
return this.transport.performRequest{{#async}}Async{{/async}}({{type}}._INSTANCE, {{type}}._ENDPOINT, this.transportOptions);
}
{{/canBeSingleton}}
{{^canBeSingleton}}
/**
* {{description}}
*/
public {{#async}}{{TYPES.Java.Util.Concurrent.CompletableFuture}}<{{/async}}{{responseType}}{{#async}}>{{/async}} {{#camelCase}}{{id}}{{/camelCase}}({{type}} request) throws {{TYPES.Java.Io.IOException}}, {{TYPES.Client.OpenSearch._Types.OpenSearchException}} {
return this.transport.performRequest{{#async}}Async{{/async}}(request, {{type}}._ENDPOINT, this.transportOptions);
@SuppressWarnings("unchecked")
{{jsonEndpointType}} endpoint = ({{jsonEndpointType}}) {{type.name}}._ENDPOINT;

return this.transport.performRequest{{#async}}Async{{/async}}(request, endpoint, this.transportOptions);
}

/**
Expand All @@ -44,8 +60,9 @@
*/
public {{#async}}{{TYPES.Java.Util.Concurrent.CompletableFuture}}<{{/async}}{{responseType}}{{#async}}>{{/async}} {{#camelCase}}{{id}}{{/camelCase}}()
throws IOException, OpenSearchException {
return {{#camelCase}}{{id}}{{/camelCase}}(new {{type.builderType}}().build());
return this.transport.performRequest{{#async}}Async{{/async}}(new {{type.builderType}}().build(), {{type.name}}._ENDPOINT, this.transportOptions);
}
{{/hasAnyRequiredFields}}
{{/canBeSingleton}}
{{/operations}}
}
}

0 comments on commit 7f0adb6

Please sign in to comment.