Skip to content

Commit 2cee533

Browse files
committed
Enable passing dynamic parameters to RuntimeClientPlugin functions
This is a requirement for advanced use cases of Endpoint Discovery logic. Currently, only Symbols and strings are generated for parameters. In future, boolean and Map<String, String> support would be added.
1 parent 0caac5c commit 2cee533

File tree

5 files changed

+153
-62
lines changed

5 files changed

+153
-62
lines changed

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/CodegenUtils.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
import java.util.ArrayList;
1919
import java.util.List;
20+
import java.util.Map;
2021
import java.util.stream.Collectors;
22+
import software.amazon.smithy.codegen.core.CodegenException;
2123
import software.amazon.smithy.codegen.core.Symbol;
2224
import software.amazon.smithy.model.Model;
2325
import software.amazon.smithy.model.knowledge.EventStreamIndex;
@@ -134,4 +136,38 @@ static void writeStreamingMemberType(
134136
+ " `%2$s` defined in {@link %1$s}", containerSymbol.getName(), memberName));
135137
writer.write("export interface $1L extends $1LType {}", typeName);
136138
}
139+
140+
/**
141+
* Returns the list of function parameter key-value pairs to be written for
142+
* provided parameters map.
143+
*
144+
* @param paramsMap Map of paramters to generate a parameters string for.
145+
* @return The list of parameters to be written.
146+
*/
147+
static List<String> getFunctionParametersList(Map<String, Object> paramsMap) {
148+
List<String> functionParametersList = new ArrayList<String>();
149+
150+
if (!paramsMap.isEmpty()) {
151+
for (Map.Entry<String, Object> param : paramsMap.entrySet()) {
152+
String key = param.getKey();
153+
Object value = param.getValue();
154+
if (value instanceof Symbol) {
155+
String symbolName = ((Symbol) value).getName();
156+
if (key.equals(symbolName)) {
157+
functionParametersList.add(key);
158+
} else {
159+
functionParametersList.add(String.format("%s: %s", key, symbolName));
160+
}
161+
} else if (value instanceof String) {
162+
functionParametersList.add(String.format("%s: '%s'", key, value));
163+
} else {
164+
// Future support for param type should be added in else if.
165+
throw new CodegenException("plugin function parameters not supported for type"
166+
+ value.toString());
167+
}
168+
}
169+
}
170+
171+
return functionParametersList;
172+
}
137173
}

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/CommandGenerator.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static software.amazon.smithy.typescript.codegen.CodegenUtils.writeStreamingMemberType;
2020

2121
import java.util.List;
22+
import java.util.Map;
2223
import java.util.Optional;
2324
import java.util.stream.Collectors;
2425
import software.amazon.smithy.codegen.core.Symbol;
@@ -248,7 +249,9 @@ private void addCommandSpecificPlugins() {
248249
// the service's middleware stack.
249250
for (RuntimeClientPlugin plugin : runtimePlugins) {
250251
plugin.getPluginFunction().ifPresent(symbol -> {
251-
List<String> additionalParameters = plugin.getAdditionalPluginFunctionParameters();
252+
Map<String, Object> paramsMap = plugin.getPluginFunctionParameters(model, service, operation);
253+
List<String> additionalParameters = CodegenUtils.getFunctionParametersList(paramsMap);
254+
252255
String additionalParamsString = additionalParameters.isEmpty()
253256
? ""
254257
: ", { " + String.join(", ", additionalParameters) + "}";

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/ServiceGenerator.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.util.Comparator;
1919
import java.util.List;
20+
import java.util.Map;
2021
import java.util.Optional;
2122
import java.util.Set;
2223
import java.util.function.Consumer;
@@ -313,7 +314,9 @@ private void generateConstructor() {
313314
for (RuntimeClientPlugin plugin : runtimePlugins) {
314315
if (plugin.getResolveFunction().isPresent()) {
315316
configVariable++;
316-
List<String> additionalParameters = plugin.getAdditionalResolveFunctionParameters();
317+
Map<String, Object> paramsMap = plugin.getResolveFunctionParameters(model, service, null);
318+
List<String> additionalParameters = CodegenUtils.getFunctionParametersList(paramsMap);
319+
317320
String additionalParamsString = additionalParameters.isEmpty()
318321
? ""
319322
: ", " + String.join(", ", additionalParameters);

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/RuntimeClientPlugin.java

Lines changed: 95 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
package software.amazon.smithy.typescript.codegen.integration;
1717

18-
import java.util.ArrayList;
19-
import java.util.List;
18+
import java.util.HashMap;
19+
import java.util.Map;
2020
import java.util.Objects;
2121
import java.util.Optional;
2222
import java.util.Set;
@@ -28,7 +28,6 @@
2828
import software.amazon.smithy.model.shapes.OperationShape;
2929
import software.amazon.smithy.model.shapes.ServiceShape;
3030
import software.amazon.smithy.typescript.codegen.TypeScriptDependency;
31-
import software.amazon.smithy.utils.ListUtils;
3231
import software.amazon.smithy.utils.SmithyBuilder;
3332
import software.amazon.smithy.utils.SmithyUnstableApi;
3433
import software.amazon.smithy.utils.StringUtils;
@@ -49,9 +48,9 @@ public final class RuntimeClientPlugin implements ToSmithyBuilder<RuntimeClientP
4948
private final SymbolReference inputConfig;
5049
private final SymbolReference resolvedConfig;
5150
private final SymbolReference resolveFunction;
52-
private final List<String> additionalResolveFunctionParameters;
51+
private final FunctionParamsSupplier resolveFunctionParamsSupplier;
5352
private final SymbolReference pluginFunction;
54-
private final List<String> additionalPluginFunctionParameters;
53+
private final FunctionParamsSupplier pluginFunctionParamsSupplier;
5554
private final SymbolReference destroyFunction;
5655
private final BiPredicate<Model, ServiceShape> servicePredicate;
5756
private final OperationPredicate operationPredicate;
@@ -60,21 +59,13 @@ private RuntimeClientPlugin(Builder builder) {
6059
inputConfig = builder.inputConfig;
6160
resolvedConfig = builder.resolvedConfig;
6261
resolveFunction = builder.resolveFunction;
63-
additionalResolveFunctionParameters = ListUtils.copyOf(builder.additionalResolveFunctionParameters);
62+
resolveFunctionParamsSupplier = builder.resolveFunctionParamsSupplier;
6463
pluginFunction = builder.pluginFunction;
65-
additionalPluginFunctionParameters = ListUtils.copyOf(builder.additionalPluginFunctionParameters);
64+
pluginFunctionParamsSupplier = builder.pluginFunctionParamsSupplier;
6665
destroyFunction = builder.destroyFunction;
6766
operationPredicate = builder.operationPredicate;
6867
servicePredicate = builder.servicePredicate;
6968

70-
if (!additionalResolveFunctionParameters.isEmpty() && resolveFunction == null) {
71-
throw new IllegalStateException("Additional parameters can only be set if a resolve function is set.");
72-
}
73-
74-
if (!additionalPluginFunctionParameters.isEmpty() && pluginFunction == null) {
75-
throw new IllegalStateException("Additional parameters can only be set if a plugin function is set.");
76-
}
77-
7869
boolean allNull = (inputConfig == null) && (resolvedConfig == null) && (resolveFunction == null);
7970
boolean allSet = (inputConfig != null) && (resolvedConfig != null) && (resolveFunction != null);
8071
if (!(allNull || allSet)) {
@@ -102,6 +93,19 @@ public interface OperationPredicate {
10293
boolean test(Model model, ServiceShape service, OperationShape operation);
10394
}
10495

96+
@FunctionalInterface
97+
public interface FunctionParamsSupplier {
98+
/**
99+
* Returns dynamic parameters for resolve function.
100+
*
101+
* @param model Model the operation belongs to.
102+
* @param service Service the operation belongs to.
103+
* @param operation Operation to test.
104+
* @return Returns true if middleware should be applied to the operation.
105+
*/
106+
Map<String, Object> apply(Model model, ServiceShape service, OperationShape operation);
107+
}
108+
105109
/**
106110
* Gets the optionally present symbol reference that points to the
107111
* <em>Input configuration interface</em> for the plugin.
@@ -163,7 +167,6 @@ public Optional<SymbolReference> getResolvedConfig() {
163167
*
164168
* @return Returns the optionally present resolve function.
165169
* @see #getInputConfig()
166-
* @see #getAdditionalResolveFunctionParameters()
167170
* @see #getResolvedConfig()
168171
*/
169172
public Optional<SymbolReference> getResolveFunction() {
@@ -173,14 +176,23 @@ public Optional<SymbolReference> getResolveFunction() {
173176
/**
174177
* Gets a list of additional parameters to be supplied to the
175178
* resolve function. These parameters are to be supplied to resolve
176-
* function as Nth(N &gt; 1) positional arguments. The list is empty if
177-
* there are no additional parameters.
179+
* function as second argument. The map is empty if there are
180+
* no additional parameters.
178181
*
179-
* @return Returns the optionally present list of parameters.
180-
* @see #getResolveFunction()
182+
* @param model Model the operation belongs to.
183+
* @param service Service the operation belongs to.
184+
* @param operation Operation to test against.
185+
* @return Returns the optionally present map of parameters.
181186
*/
182-
public List<String> getAdditionalResolveFunctionParameters() {
183-
return additionalResolveFunctionParameters;
187+
public Map<String, Object> getResolveFunctionParameters(
188+
Model model,
189+
ServiceShape service,
190+
OperationShape operation
191+
) {
192+
if (resolveFunctionParamsSupplier != null) {
193+
return resolveFunctionParamsSupplier.apply(model, service, operation);
194+
}
195+
return new HashMap<String, Object>();
184196
}
185197

186198
/**
@@ -211,14 +223,23 @@ public Optional<SymbolReference> getPluginFunction() {
211223
/**
212224
* Gets a list of additional parameters to be supplied to the
213225
* plugin function. These parameters are to be supplied to plugin
214-
* function as an options hash. The list is empty if
215-
* there are no additional parameters.
226+
* function as second argument. The map is empty if there are
227+
* no additional parameters.
216228
*
217-
* @return Returns the optionally present list of parameters.
218-
* @see #getPluginFunction()
229+
* @param model Model the operation belongs to.
230+
* @param service Service the operation belongs to.
231+
* @param operation Operation to test against.
232+
* @return Returns the optionally present map of parameters.
219233
*/
220-
public List<String> getAdditionalPluginFunctionParameters() {
221-
return additionalPluginFunctionParameters;
234+
public Map<String, Object> getPluginFunctionParameters(
235+
Model model,
236+
ServiceShape service,
237+
OperationShape operation
238+
) {
239+
if (pluginFunctionParamsSupplier != null) {
240+
return pluginFunctionParamsSupplier.apply(model, service, operation);
241+
}
242+
return new HashMap<String, Object>();
222243
}
223244

224245
/**
@@ -284,7 +305,9 @@ public Builder toBuilder() {
284305
.inputConfig(inputConfig)
285306
.resolvedConfig(resolvedConfig)
286307
.resolveFunction(resolveFunction)
308+
.resolveFunctionParamsSupplier(resolveFunctionParamsSupplier)
287309
.pluginFunction(pluginFunction)
310+
.pluginFunctionParamsSupplier(pluginFunctionParamsSupplier)
288311
.destroyFunction(destroyFunction);
289312

290313
// Set these directly since their setters have mutual side-effects.
@@ -300,9 +323,7 @@ public String toString() {
300323
+ "inputConfig=" + inputConfig
301324
+ ", resolvedConfig=" + resolvedConfig
302325
+ ", resolveFunction=" + resolveFunction
303-
+ ", additionalResolveFunctionParameters=" + additionalResolveFunctionParameters
304326
+ ", pluginFunction=" + pluginFunction
305-
+ ", additionalPluginFunctionParameters=" + additionalPluginFunctionParameters
306327
+ ", destroyFunction=" + destroyFunction
307328
+ '}';
308329
}
@@ -319,9 +340,9 @@ public boolean equals(Object o) {
319340
return Objects.equals(inputConfig, that.inputConfig)
320341
&& Objects.equals(resolvedConfig, that.resolvedConfig)
321342
&& Objects.equals(resolveFunction, that.resolveFunction)
322-
&& Objects.equals(additionalResolveFunctionParameters, that.additionalResolveFunctionParameters)
343+
&& Objects.equals(resolveFunctionParamsSupplier, that.resolveFunctionParamsSupplier)
323344
&& Objects.equals(pluginFunction, that.pluginFunction)
324-
&& Objects.equals(additionalPluginFunctionParameters, that.additionalPluginFunctionParameters)
345+
&& Objects.equals(pluginFunctionParamsSupplier, that.pluginFunctionParamsSupplier)
325346
&& Objects.equals(destroyFunction, that.destroyFunction)
326347
&& servicePredicate.equals(that.servicePredicate)
327348
&& operationPredicate.equals(that.operationPredicate);
@@ -339,9 +360,9 @@ public static final class Builder implements SmithyBuilder<RuntimeClientPlugin>
339360
private SymbolReference inputConfig;
340361
private SymbolReference resolvedConfig;
341362
private SymbolReference resolveFunction;
342-
private List<String> additionalResolveFunctionParameters = new ArrayList<>();
363+
private FunctionParamsSupplier resolveFunctionParamsSupplier;
343364
private SymbolReference pluginFunction;
344-
private List<String> additionalPluginFunctionParameters = new ArrayList<>();
365+
private FunctionParamsSupplier pluginFunctionParamsSupplier;
345366
private SymbolReference destroyFunction;
346367
private BiPredicate<Model, ServiceShape> servicePredicate = (model, service) -> true;
347368
private OperationPredicate operationPredicate = (model, service, operation) -> false;
@@ -433,13 +454,16 @@ public Builder resolveFunction(SymbolReference resolveFunction) {
433454
* {@link #inputConfig} must also be set.
434455
*
435456
* @param resolveFunction Function used to convert input to resolved.
436-
* @param additionalParameters Additional parameters to be generated as resolve function input.
457+
* @param resolveFunctionParamsSupplier Function which returns params to be passed as resolve function input.
437458
* @return Returns the builder.
438459
* @see #getResolveFunction()
439460
*/
440-
public Builder resolveFunction(SymbolReference resolveFunction, String... additionalParameters) {
461+
public Builder resolveFunction(
462+
SymbolReference resolveFunction,
463+
FunctionParamsSupplier resolveFunctionParamsSupplier
464+
) {
441465
this.resolveFunction = resolveFunction;
442-
this.additionalResolveFunctionParameters = ListUtils.of(additionalParameters);
466+
this.resolveFunctionParamsSupplier = resolveFunctionParamsSupplier;
443467
return this;
444468
}
445469

@@ -466,27 +490,33 @@ public Builder resolveFunction(Symbol resolveFunction) {
466490
* {@link #inputConfig} must also be set.
467491
*
468492
* @param resolveFunction Function used to convert input to resolved.
469-
* @param additionalParameters Additional parameters to be generated as resolve function input.
493+
* @param resolveFunctionParamsSupplier Function which returns params to be passed as resolve function input.
470494
* @return Returns the builder.
471495
* @see #getResolveFunction()
472496
*/
473-
public Builder resolveFunction(Symbol resolveFunction, String... additionalParameters) {
474-
return resolveFunction(SymbolReference.builder().symbol(resolveFunction).build(), additionalParameters);
497+
public Builder resolveFunction(
498+
Symbol resolveFunction,
499+
FunctionParamsSupplier resolveFunctionParamsSupplier
500+
) {
501+
return resolveFunction(
502+
SymbolReference.builder().symbol(resolveFunction).build(),
503+
resolveFunctionParamsSupplier
504+
);
475505
}
476506

477507
/**
478-
* Set additional positional input parameters to resolve function. Set
479-
* this with no arguments to remove the current parameters.
508+
* Set function which returns input parameters to resolve function. Set
509+
* function to return empty map to remove the current parameters.
480510
*
481511
* <p>If this is set, then all of {@link #resolveFunction},
482512
* {@link #resolvedConfig} and {@link #inputConfig} must also be set.
483513
*
484-
* @param additionalParameters Additional parameters to be generated as resolve function input.
514+
* @param resolveFunctionParamsSupplier Function which returns params to be passed as resolve function input.
485515
* @return Returns the builder.
486516
* @see #getResolveFunction()
487517
*/
488-
public Builder additionalResolveFunctionParameters(String... additionalParameters) {
489-
this.additionalResolveFunctionParameters = ListUtils.of(additionalParameters);
518+
public Builder resolveFunctionParamsSupplier(FunctionParamsSupplier resolveFunctionParamsSupplier) {
519+
this.resolveFunctionParamsSupplier = resolveFunctionParamsSupplier;
490520
return this;
491521
}
492522

@@ -508,13 +538,16 @@ public Builder pluginFunction(SymbolReference pluginFunction) {
508538
* commands to use a specific middleware function.
509539
*
510540
* @param pluginFunction Plugin function symbol to invoke.
511-
* @param additionalParameters Additional parameters to be generated as plugin function input.
541+
* @param pluginFunctionParamsSupplier Function which returns params to be passed as plugin function input.
512542
* @return Returns the builder.
513543
* @see #getPluginFunction()
514544
*/
515-
public Builder pluginFunction(SymbolReference pluginFunction, String... additionalParameters) {
545+
public Builder pluginFunction(
546+
SymbolReference pluginFunction,
547+
FunctionParamsSupplier pluginFunctionParamsSupplier
548+
) {
516549
this.pluginFunction = pluginFunction;
517-
this.additionalPluginFunctionParameters = ListUtils.of(additionalParameters);
550+
this.pluginFunctionParamsSupplier = pluginFunctionParamsSupplier;
518551
return this;
519552
}
520553

@@ -535,24 +568,30 @@ public Builder pluginFunction(Symbol pluginFunction) {
535568
* use a specific middleware function.
536569
*
537570
* @param pluginFunction Plugin function symbol to invoke.
538-
* @param additionalParameters Additional parameters to be generated as plugin function input.
571+
* @param pluginFunctionParamsSupplier Function which returns params to be passed as plugin function input.
539572
* @return Returns the builder.
540573
* @see #getPluginFunction()
541574
*/
542-
public Builder pluginFunction(Symbol pluginFunction, String... additionalParameters) {
543-
return pluginFunction(SymbolReference.builder().symbol(pluginFunction).build(), additionalParameters);
575+
public Builder pluginFunction(
576+
Symbol pluginFunction,
577+
FunctionParamsSupplier pluginFunctionParamsSupplier
578+
) {
579+
return pluginFunction(
580+
SymbolReference.builder().symbol(pluginFunction).build(),
581+
pluginFunctionParamsSupplier
582+
);
544583
}
545584

546585
/**
547-
* Set additional positional input parameters to plugin function. Set
548-
* this with no arguments to remove the current parameters.
586+
* Set function which returns input parameters to plugin function. Set
587+
* function to return empty map to remove the current parameters.
549588
*
550-
* @param additionalParameters Additional parameters to be generated as plugin function input.
589+
* @param pluginFunctionParamsSupplier Function which returns params to be passed as plugin function input.
551590
* @return Returns the builder.
552591
* @see #getPluginFunction()
553592
*/
554-
public Builder additionalPluginFunctionParameters(String... additionalParameters) {
555-
this.additionalPluginFunctionParameters = ListUtils.of(additionalParameters);
593+
public Builder pluginFunctionParamsSupplier(FunctionParamsSupplier pluginFunctionParamsSupplier) {
594+
this.pluginFunctionParamsSupplier = pluginFunctionParamsSupplier;
556595
return this;
557596
}
558597

0 commit comments

Comments
 (0)