Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-460eec0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "feature",
"category": "AWS SDK for Java v2",
"contributor": "",
"description": "Enable compiled endpoint rules for all services by default, with a fix for region parameter handling in the generated endpoint providers."
}
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,9 @@ public class CustomizationConfig {
private boolean s3ExpressAuthSupport;

/**
* Set to true to enable compiled endpoint rules. Currently defaults to false.
* Set to true to enable compiled endpoint rules. Defaults to true.
*/
private boolean enableGenerateCompiledEndpointRules = false;
private boolean enableGenerateCompiledEndpointRules = true;

/**
* Customization related to auth scheme derived from endpoints.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ private void addAccessorMethods(TypeSpec.Builder b) {
.addJavadoc("Returns the region. The region parameter may be used with the $S auth scheme.",
AwsV4AuthScheme.SCHEME_ID)
.build());
b.addMethod(MethodSpec.methodBuilder("regionId")
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
.returns(String.class)
.addJavadoc("Returns the region ID as a string. Returns null if region is not set.")
.addStatement("$T region = region()", Region.class)
.addStatement("return region == null ? null : region.id()")
.build());
}

if (authSchemeSpecUtils.hasSigV4aSupport()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ private void addFieldsAndAccessors(TypeSpec.Builder b) {
.returns(Region.class)
.addStatement("return region")
.build());

b.addMethod(MethodSpec.methodBuilder("regionId")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.returns(String.class)
.addStatement("return region == null ? null : region.id()")
.build());
}

if (authSchemeSpecUtils.hasSigV4aSupport()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.rules.endpoints.BuiltInParameter;
import software.amazon.awssdk.codegen.model.rules.endpoints.ParameterModel;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetUtils;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;

Expand Down Expand Up @@ -56,6 +58,9 @@ public TypeSpec poetSpec() {
parameters().forEach((name, model) -> {
b.addField(endpointRulesSpecUtils.parameterClassField(name, model));
b.addMethod(endpointRulesSpecUtils.parameterClassAccessorMethod(name, model));
if (model.getBuiltInEnum() == BuiltInParameter.AWS_REGION) {
b.addMethod(regionIdAccessorMethod(name));
}
});

b.addMethod(toBuilderMethod());
Expand Down Expand Up @@ -156,6 +161,22 @@ private String variableName(String name) {
return intermediateModel.getNamingStrategy().getVariableName(name);
}

/**
* Creates a convenience accessor for Region-typed parameters that returns the region ID as a String.
*/
private MethodSpec regionIdAccessorMethod(String name) {
String varName = variableName(name);
String methodName = endpointRulesSpecUtils.paramMethodName(name) + "Id";
return MethodSpec.methodBuilder(methodName)
.addModifiers(Modifier.PUBLIC)
.addJavadoc("Returns the region ID (the {@link $T#id()} value) as a String,"
+ " or null if region is not set.",
Region.class)
.returns(String.class)
.addStatement("return $N == null ? null : $N.id()", varName, varName)
.build();
}

private MethodSpec.Builder toBuilderConstructor() {
MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder();
constructorBuilder.addModifiers(Modifier.PRIVATE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ public List<String> rulesEngineResourceFiles() {
}

public List<String> rulesEngineFilesFromDirectory(URL location) {
return rulesEngineFilesFromDirectory(location, RULES_ENGINE_RESOURCE_FILES_PREFIX);
}

public List<String> rulesEngineFilesFromDirectory(URL location, String prefix) {
URI locationUri;
try {
locationUri = location.toURI();
Expand All @@ -268,7 +272,7 @@ public List<String> rulesEngineFilesFromDirectory(URL location) {
return Files.walk(directory)
// Remove the root directory if the classes, paths are expected to be relative to this directory
.map(f -> directory.relativize(f).toString())
.filter(f -> f.startsWith(RULES_ENGINE_RESOURCE_FILES_PREFIX))
.filter(f -> f.startsWith(prefix))
.collect(Collectors.toList());
} catch (IOException e) {
throw new UncheckedIOException(e);
Expand All @@ -277,6 +281,12 @@ public List<String> rulesEngineFilesFromDirectory(URL location) {

public List<String> rulesEngineResourceFiles2() {
URL currentJarUrl = EndpointRulesSpecUtils.class.getProtectionDomain().getCodeSource().getLocation();

// This would happen if the classes aren't loaded from a JAR, e.g. when unit testing
if (!currentJarUrl.toString().endsWith(".jar")) {
return rulesEngineFilesFromDirectory(currentJarUrl, "software/amazon/awssdk/codegen/rules2/");
}

try (JarFile jarFile = new JarFile(currentJarUrl.getFile())) {
return jarFile.stream()
.map(ZipEntry::getName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,6 @@ public RuleSetExpression root() {
return root;
}

public String regionParamName() {
return symbolTable.regionParamName();
}

public SymbolTable symbolTable() {
return symbolTable;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import software.amazon.awssdk.codegen.poet.PoetUtils;
import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils;
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.utils.CompletableFutureUtils;
import software.amazon.awssdk.utils.Validate;

Expand Down Expand Up @@ -94,11 +93,7 @@ private static SymbolTable initSymbolTable(Map<String, ParameterModel> parameter
parameters.forEach((k, v) -> {
builder.putParam(k, fromParameterModel(v));
if (v.getBuiltInEnum() == BuiltInParameter.AWS_REGION) {
// Region is a special case since it's already public API and uses an actual `Region` instance instead of
// `String`. We then introduce here a local with the same name but with String type such that we don't have
// to do the conversion everywhere a string represented region is used.
builder.regionParamName(k);
builder.putLocal(k, RuleRuntimeTypeMirror.STRING);
builder.addRegionParam(k);
}
});
return builder.build();
Expand Down Expand Up @@ -150,14 +145,7 @@ private MethodSpec resolveEndpointMethod() {

builder.addCode(validateRequiredParams());
builder.beginControlFlow("try");
String regionParamName = utils.regionParamName();
if (regionParamName != null) {
builder.addStatement("$T region = params.$L()", Region.class, regionParamName);
builder.addStatement("$T regionId = region == null ? null : region.id()", String.class);
builder.addStatement("$T result = $L(params, regionId)", ruleResult(), utils.root().ruleId());
} else {
builder.addStatement("$T result = $L(params)", ruleResult(), utils.root().ruleId());
}
builder.addStatement("$T result = $L(params)", ruleResult(), utils.root().ruleId());
builder.beginControlFlow("if (result.canContinue())")
.addStatement("throw $T.create($S)", SdkClientException.class, "Rule engine did not reach an error or "
+ "endpoint result")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ public RenameForCodegenVisitor(SymbolTable symbolTable) {
* Returns the new symbol table with the renamed symbols.
*/
public SymbolTable symbolTable() {
String regionParamName = symbolTable.regionParamName();
if (regionParamName != null) {
renames.regionParamName(javaName(regionParamName));
// Carry over region params with their renamed java names
for (String regionParam : symbolTable.regionParams()) {
renames.addRegionParam(javaName(regionParam));
}
return renames.build();
}
Expand All @@ -58,11 +58,14 @@ public RuleExpression visitVariableReferenceExpression(VariableReferenceExpressi
RuleType type = symbolTable.paramType(name);
String newName = javaName(name);
renames.putParam(newName, type);
// Region params return a Region object in Java but the rules use it as a String.
// Access the "{name}Id" method which returns the region ID as a String (null-safe).
String accessorName = symbolTable.isRegionParam(name) ? newName + "Id" : newName;
return MemberAccessExpression
.builder()
.type(e.type())
.source(VariableReferenceExpression.builder().variableName("params").build())
.name(newName)
.name(accessorName)
.build();
}
return e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@
package software.amazon.awssdk.codegen.poet.rules2;

import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import software.amazon.awssdk.utils.Validate;

public final class SymbolTable {
private final Map<String, RuleType> params;
private final Map<String, RuleType> locals;
private final String regionParamName;
private final Set<String> regionParams;

SymbolTable(Builder builder) {
this.params = Collections.unmodifiableMap(new LinkedHashMap<>(builder.params));
this.locals = Collections.unmodifiableMap(new LinkedHashMap<>(builder.locals));
this.regionParamName = builder.regionParamName;
this.regionParams = Collections.unmodifiableSet(new HashSet<>(builder.regionParams));
}

public static Builder builder() {
Expand Down Expand Up @@ -59,8 +61,20 @@ public Map<String, RuleType> params() {
return params;
}

public String regionParamName() {
return regionParamName;
/**
* Returns the set of parameter names that are Region-typed in Java (i.e., the Java getter returns {@code Region}
* rather than {@code String}). The codegen needs to append {@code .id()} when accessing these params to convert
* to the String value expected by the endpoint rules.
*/
public Set<String> regionParams() {
return regionParams;
}

/**
* Returns true if the given parameter name is a Region-typed param that needs {@code .id()} appended.
*/
public boolean isRegionParam(String name) {
return regionParams.contains(name);
}

public Builder toBuilder() {
Expand All @@ -70,15 +84,15 @@ public Builder toBuilder() {
public static class Builder {
private final Map<String, RuleType> params = new LinkedHashMap<>();
private final Map<String, RuleType> locals = new LinkedHashMap<>();
private String regionParamName;
private final Set<String> regionParams = new HashSet<>();

public Builder() {
}

public Builder(SymbolTable table) {
this.params.putAll(table.params);
this.locals.putAll(table.locals);
this.regionParamName = table.regionParamName;
this.regionParams.addAll(table.regionParams);
}

public Builder putParam(String name, RuleType type) {
Expand All @@ -99,8 +113,8 @@ public RuleType local(String name) {
return locals.get(name);
}

public Builder regionParamName(String regionParamName) {
this.regionParamName = regionParamName;
public Builder addRegionParam(String name) {
regionParams.add(Validate.paramNotNull(name, "name"));
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public Region region() {
return region;
}

@Override
public String regionId() {
return region == null ? null : region.id();
}

@Override
public RegionSet regionSet() {
return regionSet;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ static Builder builder() {
*/
Region region();

/**
* Returns the region ID as a string. Returns null if region is not set.
*/
default String regionId() {
Region region = region();
return region == null ? null : region.id();
}

/**
* Returns the RegionSet. The regionSet parameter may be used with the "aws.auth#sigv4a" auth scheme.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public Region region() {
return region;
}

@Override
public String regionId() {
return region == null ? null : region.id();
}

@Override
public QueryAuthSchemeParams.Builder toBuilder() {
return new Builder(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ static Builder builder() {
*/
Region region();

/**
* Returns the region ID as a string. Returns null if region is not set.
*/
default String regionId() {
Region region = region();
return region == null ? null : region.id();
}

/**
* Returns a {@link Builder} to customize the parameters.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ public Region region() {
return region;
}

@Override
public String regionId() {
return region == null ? null : region.id();
}

@Override
public RegionSet regionSet() {
return regionSet;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ public Region region() {
return region;
}

@Override
public String regionId() {
return region == null ? null : region.id();
}

@Override
public RegionSet regionSet() {
return regionSet;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ static Builder fromEndpointParams(QueryEndpointParams endpointParams) {
*/
Region region();

/**
* Returns the region ID as a string. Returns null if region is not set.
*/
default String regionId() {
Region region = region();
return region == null ? null : region.id();
}

/**
* Returns the RegionSet. The regionSet parameter may be used with the "aws.auth#sigv4a" auth scheme.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ static Builder fromEndpointParams(QueryEndpointParams endpointParams) {
*/
Region region();

/**
* Returns the region ID as a string. Returns null if region is not set.
*/
default String regionId() {
Region region = region();
return region == null ? null : region.id();
}

/**
* Returns the RegionSet. The regionSet parameter may be used with the "aws.auth#sigv4a" auth scheme.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ public Region region() {
return region;
}

/**
* Returns the region ID (the {@link Region#id()} value) as a String, or null if region is not set.
*/
public String regionId() {
return region == null ? null : region.id();
}

public Boolean useDualStackEndpoint() {
return useDualStackEndpoint;
}
Expand Down
Loading
Loading