Skip to content
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

Adds support for integrating client members via plugins #301

Merged
merged 2 commits into from
Jun 17, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public void run() {
writer.write("if params == nil { params = &$T{} }", inputSymbol);
writer.write("");

writer.write("result, metadata, err := c.invokeOperation(ctx, $S, params, optFns, $L)",
writer.write("result, metadata, err := c.invokeOperation(ctx, $S, params, optFns, c.$L)",
operationSymbol.getName(), getAddOperationMiddlewareFuncName(operationSymbol));
writer.write("if err != nil { return nil, err }");
writer.write("");
Expand Down Expand Up @@ -151,7 +151,7 @@ private void generateAddOperationMiddleware() {
Symbol stackSymbol = SymbolUtils.createPointableSymbolBuilder("Stack", SmithyGoDependency.SMITHY_MIDDLEWARE)
.build();

writer.openBlock("func $L(stack $P, options Options) (err error) {", "}",
writer.openBlock("func (c *Client) $L(stack $P, options Options) (err error) {", "}",
getAddOperationMiddlewareFuncName(operationSymbol), stackSymbol,
() -> {
generateOperationProtocolMiddlewareAdders();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import java.util.stream.Collectors;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.go.codegen.integration.ClientMember;
import software.amazon.smithy.go.codegen.integration.ClientMemberResolver;
import software.amazon.smithy.go.codegen.integration.ConfigField;
import software.amazon.smithy.go.codegen.integration.ConfigFieldResolver;
import software.amazon.smithy.go.codegen.integration.GoIntegration;
Expand Down Expand Up @@ -82,13 +84,32 @@ public void run() {
CodegenUtils.getServiceTitle(service, "the API")));
writer.openBlock("type $T struct {", "}", serviceSymbol, () -> {
writer.write("options $L", CONFIG_NAME);

// Add client members resolved from runtime plugins to the client struct.
for (ClientMember clientMember : getAllClientMembers()) {
writer.write("");
clientMember.getDocumentation().ifPresent(writer::writeDocs);
writer.write("$L $P", clientMember.getName(), clientMember.getType());
}
});

generateConstructor(serviceSymbol);
generateConfig();
generateClientInvokeOperation();
}

private void writeClientMemberResolvers(
GoWriter writer,
RuntimeClientPlugin plugin,
Predicate<ClientMemberResolver> predicate
) {
plugin.getClientMemberResolvers().stream().filter(predicate)
.forEach(resolver -> {
writer.write("$T(client)", resolver.getResolver());
writer.write("");
});
}

private void writeConfigFieldResolvers(
GoWriter writer,
RuntimeClientPlugin plugin,
Expand Down Expand Up @@ -136,6 +157,11 @@ private void generateConstructor(Symbol serviceSymbol) {
writer.write("options: options,");
}).write("");

// Run any client member resolver functions registered by runtime plugins.
for (RuntimeClientPlugin plugin : plugins) {
writeClientMemberResolvers(writer, plugin, resolver -> true);
}

writer.write("return client");
});
}
Expand Down Expand Up @@ -179,7 +205,6 @@ private void generateConfig() {
writer.write("o.$L = v", configField.getName());
});
}).write("");

});

generateApplicationProtocolTypes();
Expand Down Expand Up @@ -209,6 +234,21 @@ private List<ConfigField> getAllConfigFields() {
.collect(Collectors.toList());
}

private List<ClientMember> getAllClientMembers() {
List<ClientMember> clientMembers = new ArrayList<>();
for (RuntimeClientPlugin runtimeClientPlugin : runtimePlugins) {
if (!runtimeClientPlugin.matchesService(model, service)) {
continue;
}

clientMembers.addAll(runtimeClientPlugin.getClientMembers());
}
return clientMembers.stream()
.distinct()
.sorted(Comparator.comparing(ClientMember::getName))
.collect(Collectors.toList());
}

private void generateApplicationProtocolConfig() {
ensureSupportedProtocol();
writer.writeDocs(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Copyright 2021 Amazon.com, Inc. or its affiliates. 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.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 software.amazon.smithy.go.codegen.integration;

import java.util.Objects;
import java.util.Optional;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.utils.SmithyBuilder;
import software.amazon.smithy.utils.ToSmithyBuilder;

/**
* Represents a member field on a client struct.
*/
public class ClientMember implements ToSmithyBuilder<ClientMember> {
private final String name;
private final Symbol type;
private final String documentation;

public ClientMember(Builder builder) {
this.name = Objects.requireNonNull(builder.name);
this.type = Objects.requireNonNull(builder.type);
this.documentation = builder.documentation;
}

/**
* @return Returns the name of the client member field.
*/
public String getName() {
return name;
}

/**
* @return Returns the type Symbol for the member field.
*/
public Symbol getType() {
return type;
}

/**
* @return Gets the optional documentation for the member field.
*/
public Optional<String> getDocumentation() {
return Optional.ofNullable(documentation);
}

@Override
public SmithyBuilder<ClientMember> toBuilder() {
return builder().type(type).name(name).documentation(documentation);
}

public static Builder builder() {
return new Builder();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ClientMember that = (ClientMember) o;
return Objects.equals(getName(), that.getName())
&& Objects.equals(getType(), that.getType())
&& Objects.equals(getDocumentation(), that.getDocumentation());
}

@Override
public int hashCode() {
return Objects.hash(getName(), getType(), getDocumentation());
}

/**
* Builds a ClientMember.
*/
public static class Builder implements SmithyBuilder<ClientMember> {
private String name;
private Symbol type;
private String documentation;

@Override
public ClientMember build() {
return new ClientMember(this);
}

/**
* Set the name of the member field on client.
*
* @param name is the name of the field on the client.
* @return Returns the builder.
*/
public Builder name(String name) {
this.name = name;
return this;
}

/**
* Sets the type of the client field.
*
* @param type A Symbol representing the type of the client field.
* @return Returns the builder.
*/
public Builder type(Symbol type) {
this.type = type;
return this;
}

/**
* Sets the documentation for the client field.
*
* @param documentation The documentation for the client field.
* @return Returns the builder.
*/
public Builder documentation(String documentation) {
this.documentation = documentation;
return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. 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.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 software.amazon.smithy.go.codegen.integration;

import java.util.Objects;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.utils.SmithyBuilder;

/**
* Represent symbol that points to a function that operates
* on the client member fields during client construction.
*
* Any configuration that a plugin requires in order to function should be
* checked in this function, either setting a default value if possible or
* returning an error if not.
*/
public final class ClientMemberResolver {
private final Symbol resolver;
skotambkar marked this conversation as resolved.
Show resolved Hide resolved

private ClientMemberResolver(Builder builder) {
resolver = SmithyBuilder.requiredState("resolver", builder.resolver);
}

public Symbol getResolver() {
return resolver;
}

public static Builder builder() {
return new Builder();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ClientMemberResolver that = (ClientMemberResolver) o;
return resolver.equals(that.resolver);
}

/**
* Returns a hash code value for the object.
* @return the hash code.
*/
@Override
public int hashCode() {
return Objects.hash(resolver);
}

public static class Builder implements SmithyBuilder<ClientMemberResolver> {
private Symbol resolver;

public Builder resolver(Symbol resolver) {
this.resolver = resolver;
return this;
}

@Override
public ClientMemberResolver build() {
return new ClientMemberResolver(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,22 +153,6 @@ default List<ProtocolGenerator> getProtocolGenerators() {
return Collections.emptyList();
}

/**
* Adds additional client config interface fields.
*
* @param settings Settings used to generate.
* @param model Model to generate from.
* @param symbolProvider Symbol provider used for codegen.
* @param writer TypeScript writer to write to.
*/
default void addConfigInterfaceFields(
GoSettings settings,
Model model,
SymbolProvider symbolProvider,
GoWriter writer
) {
// pass
}

/**
* Processes the finalized model before runtime plugins are consumed and
Expand Down
Loading