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