diff --git a/.changes/next-release/feature-AWSSDKforJavav-0ca473f.json b/.changes/next-release/feature-AWSSDKforJavav-0ca473f.json new file mode 100644 index 000000000000..58784ed4c93b --- /dev/null +++ b/.changes/next-release/feature-AWSSDKforJavav-0ca473f.json @@ -0,0 +1,6 @@ +{ + "type": "feature", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Migrate PartitionMetadata code generation from endpoints.json to partitions.json" +} diff --git a/codegen-lite-maven-plugin/src/main/java/software/amazon/awssdk/codegen/lite/maven/plugin/RegionGenerationMojo.java b/codegen-lite-maven-plugin/src/main/java/software/amazon/awssdk/codegen/lite/maven/plugin/RegionGenerationMojo.java index 10422e931450..b4627d4a8404 100644 --- a/codegen-lite-maven-plugin/src/main/java/software/amazon/awssdk/codegen/lite/maven/plugin/RegionGenerationMojo.java +++ b/codegen-lite-maven-plugin/src/main/java/software/amazon/awssdk/codegen/lite/maven/plugin/RegionGenerationMojo.java @@ -73,7 +73,7 @@ public void execute() throws MojoExecutionException { Partitions partitions = RegionMetadataLoader.build(endpoints); PartitionsRegionsMetadata regionPartitions = PartitionsRegionsMetadataLoader.build(partitionsJson); - generatePartitionMetadataClass(baseSourcesDirectory, partitions); + generatePartitionMetadataClass(baseSourcesDirectory, regionPartitions); generateRegionClass(baseSourcesDirectory, regionPartitions); generateServiceMetadata(baseSourcesDirectory, partitions); generateRegions(baseSourcesDirectory, regionPartitions); @@ -86,7 +86,7 @@ public void execute() throws MojoExecutionException { project.addTestCompileSourceRoot(testsDirectory.toFile().getAbsolutePath()); } - public void generatePartitionMetadataClass(Path baseSourcesDirectory, Partitions partitions) { + public void generatePartitionMetadataClass(Path baseSourcesDirectory, PartitionsRegionsMetadata partitions) { Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(PARTITION_METADATA_BASE, ".", "/")); partitions.getPartitions() .forEach(p -> new CodeGenerator(sourcesDirectory.toString(), diff --git a/codegen-lite/src/main/java/software/amazon/awssdk/codegen/lite/regions/PartitionMetadataGenerator.java b/codegen-lite/src/main/java/software/amazon/awssdk/codegen/lite/regions/PartitionMetadataGenerator.java index 729a057e4ff9..be437c88d7b5 100644 --- a/codegen-lite/src/main/java/software/amazon/awssdk/codegen/lite/regions/PartitionMetadataGenerator.java +++ b/codegen-lite/src/main/java/software/amazon/awssdk/codegen/lite/regions/PartitionMetadataGenerator.java @@ -15,7 +15,6 @@ package software.amazon.awssdk.codegen.lite.regions; -import static java.util.Collections.emptyList; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PRIVATE; import static javax.lang.model.element.Modifier.PUBLIC; @@ -29,7 +28,9 @@ import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -38,16 +39,35 @@ import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.codegen.lite.PoetClass; import software.amazon.awssdk.codegen.lite.Utils; -import software.amazon.awssdk.codegen.lite.regions.model.Partition; +import software.amazon.awssdk.codegen.lite.regions.model.PartitionRegionsMetadata; import software.amazon.awssdk.utils.ImmutableMap; +import software.amazon.awssdk.utils.StringUtils; public class PartitionMetadataGenerator implements PoetClass { - private final Partition partition; + /** + * Hardcoded mapping of partition IDs to display names. + * This preserves backward compatibility since partitions.json only provides + * partition IDs, while the old endpoints.json had separate partitionName fields. + * New partitions will fall back to using their ID as the display name. + */ + private static final Map PARTITION_DISPLAY_NAMES = + ImmutableMap.builder() + .put("aws", "AWS Standard") + .put("aws-cn", "AWS China") + .put("aws-us-gov", "AWS GovCloud (US)") + .put("aws-iso", "AWS ISO (US)") + .put("aws-iso-b", "AWS ISOB (US)") + .put("aws-iso-e", "AWS ISOE (Europe)") + .put("aws-iso-f", "AWS ISOF") + .put("aws-eusc", "AWS EUSC") + .build(); + + private final PartitionRegionsMetadata partition; private final String basePackage; private final String regionBasePackage; - public PartitionMetadataGenerator(Partition partition, + public PartitionMetadataGenerator(PartitionRegionsMetadata partition, String basePackage, String regionBasePackage) { this.partition = partition; @@ -80,11 +100,12 @@ public TypeSpec poetClass() { .build()) .addField(FieldSpec.builder(String.class, "ID") .addModifiers(PRIVATE, FINAL, STATIC) - .initializer("$S", partition.getPartition()) + .initializer("$S", partition.getId()) .build()) .addField(FieldSpec.builder(String.class, "NAME") .addModifiers(PRIVATE, FINAL, STATIC) - .initializer("$S", partition.getPartitionName()) + .initializer("$S", PARTITION_DISPLAY_NAMES.getOrDefault( + partition.getId(), partition.getId())) .build()) .addField(FieldSpec.builder(String.class, "REGION_REGEX") .addModifiers(PRIVATE, FINAL, STATIC) @@ -103,18 +124,33 @@ private CodeBlock dnsSuffixes() { CodeBlock.builder() .add("$T.<$T, $T>builder()", ImmutableMap.class, partitionEndpointKeyClass(), String.class); + String defaultDnsSuffix = partition.getOutputs().getDnsSuffix(); + String dualStackDnsSuffix = partition.getOutputs().getDualStackDnsSuffix(); + boolean supportsFips = partition.getOutputs().isSupportsFIPS(); + boolean supportsDualStack = partition.getOutputs().isSupportsDualStack(); + builder.add(".put(") - .add(partitionEndpointKey(emptyList())) - .add(", $S)", partition.getDnsSuffix()); - - if (partition.getDefaults() != null) { - partition.getDefaults().getVariants().forEach(variant -> { - if (variant.getDnsSuffix() != null) { - builder.add(".put(") - .add(partitionEndpointKey(variant.getTags())) - .add(", $S)", variant.getDnsSuffix()); - } - }); + .add(partitionEndpointKey(Collections.emptyList())) + .add(", $S)", defaultDnsSuffix); + + if (supportsFips) { + builder.add(".put(") + .add(partitionEndpointKey(Collections.singletonList("fips"))) + .add(", $S)", defaultDnsSuffix); + } + + if (supportsDualStack && supportsFips) { + validateDualStackDnsSuffix(dualStackDnsSuffix); + builder.add(".put(") + .add(partitionEndpointKey(Arrays.asList("dualstack", "fips"))) + .add(", $S)", dualStackDnsSuffix); + } + + if (supportsDualStack) { + validateDualStackDnsSuffix(dualStackDnsSuffix); + builder.add(".put(") + .add(partitionEndpointKey(Collections.singletonList("dualstack"))) + .add(", $S)", dualStackDnsSuffix); } return builder.add(".build()").build(); @@ -125,19 +161,32 @@ private CodeBlock hostnames() { CodeBlock.builder() .add("$T.<$T, $T>builder()", ImmutableMap.class, partitionEndpointKeyClass(), String.class); + boolean supportsFips = partition.getOutputs().isSupportsFIPS(); + boolean supportsDualStack = partition.getOutputs().isSupportsDualStack(); + String dualStackDnsSuffix = partition.getOutputs().getDualStackDnsSuffix(); - if (partition.getDefaults() != null) { + builder.add(".put(") + .add(partitionEndpointKey(Collections.emptyList())) + .add(", $S)", "{service}.{region}.{dnsSuffix}"); + + if (supportsFips) { + builder.add(".put(") + .add(partitionEndpointKey(Collections.singletonList("fips"))) + .add(", $S)", "{service}-fips.{region}.{dnsSuffix}"); + } + + if (supportsDualStack && supportsFips) { + validateDualStackDnsSuffix(dualStackDnsSuffix); + builder.add(".put(") + .add(partitionEndpointKey(Arrays.asList("dualstack", "fips"))) + .add(", $S)", "{service}-fips.{region}.{dnsSuffix}"); + } + + if (supportsDualStack) { + validateDualStackDnsSuffix(dualStackDnsSuffix); builder.add(".put(") - .add(partitionEndpointKey(emptyList())) - .add(", $S)", partition.getDefaults().getHostname()); - - partition.getDefaults().getVariants().forEach(variant -> { - if (variant.getHostname() != null) { - builder.add(".put(") - .add(partitionEndpointKey(variant.getTags())) - .add(", $S)", variant.getHostname()); - } - }); + .add(partitionEndpointKey(Collections.singletonList("dualstack"))) + .add(", $S)", "{service}.{region}.{dnsSuffix}"); } return builder.add(".build()").build(); @@ -165,7 +214,7 @@ private MethodSpec hostnameGetter() { @Override public ClassName className() { - return ClassName.get(basePackage, Stream.of(partition.getPartition().split("-")) + return ClassName.get(basePackage, Stream.of(partition.getId().split("-")) .map(Utils::capitalize) .collect(Collectors.joining()) + "PartitionMetadata"); } @@ -179,6 +228,13 @@ private MethodSpec getter(String methodName, String field) { .build(); } + private void validateDualStackDnsSuffix(String dualStackDnsSuffix) { + if (StringUtils.isBlank(dualStackDnsSuffix)) { + throw new IllegalStateException("Partition " + partition.getId() + + " claims to support dualstack but dualStackDnsSuffix is null or empty"); + } + } + private CodeBlock partitionEndpointKey(Collection tags) { CodeBlock.Builder result = CodeBlock.builder(); result.add("$T.builder()", partitionEndpointKeyClass()); diff --git a/codegen-lite/src/test/java/software/amazon/awssdk/codegen/lite/regions/RegionGenerationTest.java b/codegen-lite/src/test/java/software/amazon/awssdk/codegen/lite/regions/RegionGenerationTest.java index 2ace744a0392..4de165946a52 100644 --- a/codegen-lite/src/test/java/software/amazon/awssdk/codegen/lite/regions/RegionGenerationTest.java +++ b/codegen-lite/src/test/java/software/amazon/awssdk/codegen/lite/regions/RegionGenerationTest.java @@ -105,7 +105,7 @@ public void serviceMetadataProviderClass() { @Test public void partitionMetadataClass() { - PartitionMetadataGenerator partitionMetadataGenerator = new PartitionMetadataGenerator(partitions.getPartitions().get(0), + PartitionMetadataGenerator partitionMetadataGenerator = new PartitionMetadataGenerator(partitionsRegions.getPartitions().get(0), PARTITION_METADATA_BASE, REGION_BASE); diff --git a/codegen-lite/src/test/resources/software/amazon/awssdk/codegen/lite/regions/partition-metadata.java b/codegen-lite/src/test/resources/software/amazon/awssdk/codegen/lite/regions/partition-metadata.java index 6347fd1f5b44..46d1cd486404 100644 --- a/codegen-lite/src/test/resources/software/amazon/awssdk/codegen/lite/regions/partition-metadata.java +++ b/codegen-lite/src/test/resources/software/amazon/awssdk/codegen/lite/regions/partition-metadata.java @@ -30,7 +30,7 @@ public final class AwsPartitionMetadata implements PartitionMetadata { private static final String NAME = "AWS Standard"; - private static final String REGION_REGEX = "^(us|eu|ap|sa|ca|me|af)\\-\\w+\\-\\d+$"; + private static final String REGION_REGEX = "^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$"; @Override public String id() { diff --git a/test/region-testing/pom.xml b/test/region-testing/pom.xml index b7d9f4325b9a..4c6e46986220 100644 --- a/test/region-testing/pom.xml +++ b/test/region-testing/pom.xml @@ -102,6 +102,7 @@ ${basedir}/src/test/resources/variants-test-endpoints.json + ${basedir}/src/test/resources/variants-test-partitions.json diff --git a/test/region-testing/src/test/resources/variants-test-partitions.json b/test/region-testing/src/test/resources/variants-test-partitions.json new file mode 100644 index 000000000000..398403e43c1a --- /dev/null +++ b/test/region-testing/src/test/resources/variants-test-partitions.json @@ -0,0 +1,273 @@ +{ + "partitions": [ + { + "id": "aws", + "outputs": { + "dnsSuffix": "amazonaws.com", + "dualStackDnsSuffix": "api.aws", + "implicitGlobalRegion": "us-east-1", + "name": "aws", + "supportsDualStack": true, + "supportsFIPS": true + }, + "regionRegex": "^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$", + "regions": { + "af-south-1": { + "description": "Africa (Cape Town)" + }, + "ap-east-1": { + "description": "Asia Pacific (Hong Kong)" + }, + "ap-east-2": { + "description": "Asia Pacific (Taipei)" + }, + "ap-northeast-1": { + "description": "Asia Pacific (Tokyo)" + }, + "ap-northeast-2": { + "description": "Asia Pacific (Seoul)" + }, + "ap-northeast-3": { + "description": "Asia Pacific (Osaka)" + }, + "ap-south-1": { + "description": "Asia Pacific (Mumbai)" + }, + "ap-south-2": { + "description": "Asia Pacific (Hyderabad)" + }, + "ap-southeast-1": { + "description": "Asia Pacific (Singapore)" + }, + "ap-southeast-2": { + "description": "Asia Pacific (Sydney)" + }, + "ap-southeast-3": { + "description": "Asia Pacific (Jakarta)" + }, + "ap-southeast-4": { + "description": "Asia Pacific (Melbourne)" + }, + "ap-southeast-5": { + "description": "Asia Pacific (Malaysia)" + }, + "ap-southeast-6": { + "description": "Asia Pacific (New Zealand)" + }, + "ap-southeast-7": { + "description": "Asia Pacific (Thailand)" + }, + "aws-global": { + "description": "aws global region" + }, + "ca-central-1": { + "description": "Canada (Central)" + }, + "ca-west-1": { + "description": "Canada West (Calgary)" + }, + "eu-central-1": { + "description": "Europe (Frankfurt)" + }, + "eu-central-2": { + "description": "Europe (Zurich)" + }, + "eu-north-1": { + "description": "Europe (Stockholm)" + }, + "eu-south-1": { + "description": "Europe (Milan)" + }, + "eu-south-2": { + "description": "Europe (Spain)" + }, + "eu-west-1": { + "description": "Europe (Ireland)" + }, + "eu-west-2": { + "description": "Europe (London)" + }, + "eu-west-3": { + "description": "Europe (Paris)" + }, + "il-central-1": { + "description": "Israel (Tel Aviv)" + }, + "me-central-1": { + "description": "Middle East (UAE)" + }, + "me-south-1": { + "description": "Middle East (Bahrain)" + }, + "mx-central-1": { + "description": "Mexico (Central)" + }, + "sa-east-1": { + "description": "South America (Sao Paulo)" + }, + "us-east-1": { + "description": "US East (N. Virginia)" + }, + "us-east-2": { + "description": "US East (Ohio)" + }, + "us-west-1": { + "description": "US West (N. California)" + }, + "us-west-2": { + "description": "US West (Oregon)" + } + } + }, + { + "id": "aws-cn", + "outputs": { + "dnsSuffix": "amazonaws.com.cn", + "dualStackDnsSuffix": "api.amazonwebservices.com.cn", + "implicitGlobalRegion": "cn-northwest-1", + "name": "aws-cn", + "supportsDualStack": true, + "supportsFIPS": true + }, + "regionRegex": "^cn\\-\\w+\\-\\d+$", + "regions": { + "aws-cn-global": { + "description": "aws-cn global region" + }, + "cn-north-1": { + "description": "China (Beijing)" + }, + "cn-northwest-1": { + "description": "China (Ningxia)" + } + } + }, + { + "id": "aws-eusc", + "outputs": { + "dnsSuffix": "amazonaws.eu", + "dualStackDnsSuffix": "api.amazonwebservices.eu", + "implicitGlobalRegion": "eusc-de-east-1", + "name": "aws-eusc", + "supportsDualStack": true, + "supportsFIPS": true + }, + "regionRegex": "^eusc\\-(de)\\-\\w+\\-\\d+$", + "regions": { + "eusc-de-east-1": { + "description": "EU (Germany)" + } + } + }, + { + "id": "aws-iso", + "outputs": { + "dnsSuffix": "c2s.ic.gov", + "implicitGlobalRegion": "us-iso-east-1", + "name": "aws-iso" + }, + "regionRegex": "^us\\-iso\\-\\w+\\-\\d+$", + "regions": { + "aws-iso-global": { + "description": "aws-iso global region" + }, + "us-iso-east-1": { + "description": "US ISO East" + }, + "us-iso-west-1": { + "description": "US ISO WEST" + } + } + }, + { + "id": "aws-iso-b", + "outputs": { + "dnsSuffix": "sc2s.sgov.gov", + "dualStackDnsSuffix": "api.aws.scloud", + "implicitGlobalRegion": "us-isob-east-1", + "name": "aws-iso-b", + "supportsDualStack": true, + "supportsFIPS": true + }, + "regionRegex": "^us\\-isob\\-\\w+\\-\\d+$", + "regions": { + "aws-iso-b-global": { + "description": "aws-iso-b global region" + }, + "us-isob-east-1": { + "description": "US ISOB East (Ohio)" + }, + "us-isob-west-1": { + "description": "US ISOB West" + } + } + }, + { + "id": "aws-iso-e", + "outputs": { + "dnsSuffix": "cloud.adc-e.uk", + "dualStackDnsSuffix": "api.cloud-aws.adc-e.uk", + "implicitGlobalRegion": "eu-isoe-west-1", + "name": "aws-iso-e", + "supportsDualStack": true, + "supportsFIPS": true + }, + "regionRegex": "^eu\\-isoe\\-\\w+\\-\\d+$", + "regions": { + "aws-iso-e-global": { + "description": "aws-iso-e global region" + }, + "eu-isoe-west-1": { + "description": "EU ISOE West" + } + } + }, + { + "id": "aws-iso-f", + "outputs": { + "dnsSuffix": "csp.hci.ic.gov", + "dualStackDnsSuffix": "api.aws.hci.ic.gov", + "implicitGlobalRegion": "us-isof-south-1", + "name": "aws-iso-f", + "supportsDualStack": true, + "supportsFIPS": true + }, + "regionRegex": "^us\\-isof\\-\\w+\\-\\d+$", + "regions": { + "aws-iso-f-global": { + "description": "aws-iso-f global region" + }, + "us-isof-east-1": { + "description": "US ISOF EAST" + }, + "us-isof-south-1": { + "description": "US ISOF SOUTH" + } + } + }, + { + "id": "aws-us-gov", + "outputs": { + "dnsSuffix": "amazonaws.com", + "dualStackDnsSuffix": "api.aws", + "implicitGlobalRegion": "us-gov-west-1", + "name": "aws-us-gov", + "supportsDualStack": true, + "supportsFIPS": true + }, + "regionRegex": "^us\\-gov\\-\\w+\\-\\d+$", + "regions": { + "aws-us-gov-global": { + "description": "aws-us-gov global region" + }, + "us-gov-east-1": { + "description": "AWS GovCloud (US-East)" + }, + "us-gov-west-1": { + "description": "AWS GovCloud (US-West)" + } + } + } + ], + "version": "1.1" +}