Skip to content

Commit 97460f3

Browse files
committed
feat(cbor): add protocol resolution priority system
1 parent 4c692ae commit 97460f3

File tree

6 files changed

+219
-21
lines changed

6 files changed

+219
-21
lines changed

private/smithy-rpcv2-cbor/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,25 @@
2020
"@aws-crypto/sha256-js": "5.2.0",
2121
"@aws-sdk/types": "latest",
2222
"@smithy/config-resolver": "^3.0.5",
23-
"@smithy/core": "^2.3.2",
23+
"@smithy/core": "^2.4.0",
2424
"@smithy/fetch-http-handler": "^3.2.4",
2525
"@smithy/hash-node": "^3.0.3",
2626
"@smithy/invalid-dependency": "^3.0.3",
2727
"@smithy/middleware-content-length": "^3.0.5",
28-
"@smithy/middleware-retry": "^3.0.14",
28+
"@smithy/middleware-retry": "^3.0.15",
2929
"@smithy/middleware-serde": "^3.0.3",
3030
"@smithy/middleware-stack": "^3.0.3",
3131
"@smithy/node-config-provider": "^3.1.4",
3232
"@smithy/node-http-handler": "^3.1.4",
3333
"@smithy/protocol-http": "^4.1.0",
34-
"@smithy/smithy-client": "^3.1.12",
34+
"@smithy/smithy-client": "^3.2.0",
3535
"@smithy/types": "^3.3.0",
3636
"@smithy/url-parser": "^3.0.3",
3737
"@smithy/util-base64": "^3.0.0",
3838
"@smithy/util-body-length-browser": "^3.0.0",
3939
"@smithy/util-body-length-node": "^3.0.0",
40-
"@smithy/util-defaults-mode-browser": "^3.0.14",
41-
"@smithy/util-defaults-mode-node": "^3.0.14",
40+
"@smithy/util-defaults-mode-browser": "^3.0.15",
41+
"@smithy/util-defaults-mode-node": "^3.0.15",
4242
"@smithy/util-middleware": "^3.0.3",
4343
"@smithy/util-retry": "^3.0.3",
4444
"@smithy/util-utf8": "^3.0.0",

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import java.nio.file.Paths;
1919
import java.util.ArrayList;
2020
import java.util.Collection;
21-
import java.util.HashMap;
21+
import java.util.LinkedHashMap;
2222
import java.util.List;
2323
import java.util.Map;
2424
import java.util.Set;
@@ -136,7 +136,9 @@ private ProtocolGenerator resolveProtocolGenerator(
136136
TypeScriptSettings settings
137137
) {
138138
// Collect all of the supported protocol generators.
139-
Map<ShapeId, ProtocolGenerator> generators = new HashMap<>();
139+
// Preserve insertion order as default priority order.
140+
Map<ShapeId, ProtocolGenerator> generators = new LinkedHashMap<>();
141+
140142
for (TypeScriptIntegration integration : integrations) {
141143
for (ProtocolGenerator generator : integration.getProtocolGenerators()) {
142144
generators.put(generator.getProtocol(), generator);

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

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

18+
import java.util.ArrayList;
1819
import java.util.Arrays;
1920
import java.util.Collections;
2021
import java.util.List;
@@ -36,6 +37,7 @@
3637
import software.amazon.smithy.model.shapes.ShapeId;
3738
import software.amazon.smithy.model.traits.DefaultTrait;
3839
import software.amazon.smithy.model.traits.RequiredTrait;
40+
import software.amazon.smithy.typescript.codegen.protocols.ProtocolPriority;
3941
import software.amazon.smithy.utils.SmithyUnstableApi;
4042

4143
/**
@@ -450,8 +452,13 @@ public ShapeId resolveServiceProtocol(Model model, ServiceShape service, Set<Sha
450452
+ "generate in smithy-build.json to generate this service.");
451453
}
452454

453-
return resolvedProtocols.stream()
454-
.filter(supportedProtocols::contains)
455+
List<ShapeId> protocolPriority = ProtocolPriority.getProtocolPriority(service.toShapeId());
456+
List<ShapeId> protocolPriorityList = protocolPriority != null && !protocolPriority.isEmpty()
457+
? protocolPriority
458+
: new ArrayList<>(supportedProtocols);
459+
460+
return protocolPriorityList.stream()
461+
.filter(resolvedProtocols::contains)
455462
.findFirst()
456463
.orElseThrow(() -> new UnresolvableProtocolException(String.format(
457464
"The %s service supports the following unsupported protocols %s. The following protocol "
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.amazon.smithy.typescript.codegen.protocols;
7+
8+
import java.util.ArrayList;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.Map;
12+
import software.amazon.smithy.model.shapes.ShapeId;
13+
14+
15+
/**
16+
* Allows customization of protocol selection for specific services or a global default ordering.
17+
*/
18+
public final class ProtocolPriority {
19+
private static final Map<ShapeId, List<ShapeId>> SERVICE_PROTOCOL_PRIORITY_CUSTOMIZATIONS = new HashMap<>();
20+
private static List<ShapeId> customDefaultPriority = null;
21+
22+
private ProtocolPriority() {}
23+
24+
/**
25+
* @param serviceShapeId - service scope.
26+
* @param protocolPriorityOrder - priority order of protocols.
27+
*/
28+
public static void setProtocolPriority(ShapeId serviceShapeId, List<ShapeId> protocolPriorityOrder) {
29+
SERVICE_PROTOCOL_PRIORITY_CUSTOMIZATIONS.put(serviceShapeId, protocolPriorityOrder);
30+
}
31+
32+
/**
33+
* @param defaultProtocolPriorityOrder - use for all services that don't have a more specific priority order.
34+
*/
35+
public static void setCustomDefaultProtocolPriority(List<ShapeId> defaultProtocolPriorityOrder) {
36+
customDefaultPriority = new ArrayList<>(defaultProtocolPriorityOrder);
37+
}
38+
39+
/**
40+
* @param serviceShapeId - service scope.
41+
* @return priority order of protocols or null if no override exists.
42+
*/
43+
public static List<ShapeId> getProtocolPriority(ShapeId serviceShapeId) {
44+
return SERVICE_PROTOCOL_PRIORITY_CUSTOMIZATIONS.getOrDefault(
45+
serviceShapeId,
46+
customDefaultPriority != null ? new ArrayList<>(customDefaultPriority) : null
47+
);
48+
}
49+
50+
/**
51+
* @param serviceShapeId - to unset.
52+
*/
53+
public static void deleteProtocolPriority(ShapeId serviceShapeId) {
54+
SERVICE_PROTOCOL_PRIORITY_CUSTOMIZATIONS.remove(serviceShapeId);
55+
}
56+
57+
/**
58+
* Unset the custom default priority order.
59+
*/
60+
public static void deleteCustomDefaultProtocolPriority() {
61+
customDefaultPriority = null;
62+
}
63+
}

smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/TypeScriptSettingsTest.java

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
package software.amazon.smithy.typescript.codegen;
22

3+
import java.util.LinkedHashSet;
4+
import java.util.List;
5+
import java.util.stream.Stream;
36
import org.junit.jupiter.api.Test;
7+
import org.junit.jupiter.api.extension.ExtendWith;
48
import org.junit.jupiter.params.ParameterizedTest;
59
import org.junit.jupiter.params.provider.Arguments;
610
import org.junit.jupiter.params.provider.MethodSource;
11+
import org.mockito.Mock;
12+
import org.mockito.junit.jupiter.MockitoExtension;
713
import software.amazon.smithy.model.Model;
14+
import software.amazon.smithy.model.knowledge.ServiceIndex;
815
import software.amazon.smithy.model.node.Node;
916
import software.amazon.smithy.model.node.ObjectNode;
17+
import software.amazon.smithy.model.shapes.ServiceShape;
1018
import software.amazon.smithy.model.shapes.ShapeId;
11-
12-
import java.util.stream.Stream;
19+
import software.amazon.smithy.typescript.codegen.protocols.ProtocolPriority;
20+
import software.amazon.smithy.utils.MapUtils;
1321

1422
import static org.hamcrest.MatcherAssert.assertThat;
1523
import static org.hamcrest.Matchers.equalTo;
1624
import static org.junit.jupiter.api.Assertions.assertEquals;
25+
import static org.mockito.ArgumentMatchers.any;
26+
import static org.mockito.Mockito.when;
1727

28+
@ExtendWith(MockitoExtension.class)
1829
public class TypeScriptSettingsTest {
1930

2031
@Test
@@ -87,6 +98,121 @@ private static Stream<Arguments> providePackageDescriptionTestCases() {
8798
);
8899
}
89100

101+
@Test
102+
public void resolveServiceProtocol(@Mock Model model,
103+
@Mock ServiceShape service,
104+
@Mock ServiceIndex serviceIndex) {
105+
TypeScriptSettings subject = new TypeScriptSettings();
106+
107+
// note: these are mock protocol names.
108+
ShapeId rpcv2Cbor = ShapeId.from("namespace#rpcv2Cbor");
109+
ShapeId json1_0 = ShapeId.from("namespace#json1_0");
110+
ShapeId json1_1 = ShapeId.from("namespace#json1_1");
111+
ShapeId restJson1 = ShapeId.from("namespace#restJson1");
112+
ShapeId restXml = ShapeId.from("namespace#restXml");
113+
ShapeId query = ShapeId.from("namespace#query");
114+
ShapeId serviceQuery = ShapeId.from("namespace#serviceQuery");
115+
116+
when(model.getKnowledge(any(), any())).thenReturn(serviceIndex);
117+
ShapeId serviceShapeId = ShapeId.from("namespace#Service");
118+
when(service.toShapeId()).thenReturn(serviceShapeId);
119+
120+
LinkedHashSet<ShapeId> protocolShapeIds = new LinkedHashSet<>(
121+
List.of(
122+
json1_0, json1_1, restJson1, rpcv2Cbor, restXml, query, serviceQuery
123+
)
124+
);
125+
126+
{
127+
// spec case 1.
128+
when(serviceIndex.getProtocols(service)).thenReturn(MapUtils.of(
129+
rpcv2Cbor, null,
130+
json1_0, null
131+
));
132+
ShapeId protocol = subject.resolveServiceProtocol(model, service, protocolShapeIds);
133+
// Note: JS customization JSON higher default priority than CBOR.
134+
assertEquals(json1_0, protocol);
135+
}
136+
137+
{
138+
// spec case 2.
139+
when(serviceIndex.getProtocols(service)).thenReturn(MapUtils.of(
140+
rpcv2Cbor, null
141+
));
142+
ShapeId protocol = subject.resolveServiceProtocol(model, service, protocolShapeIds);
143+
assertEquals(rpcv2Cbor, protocol);
144+
}
145+
146+
{
147+
// spec case 3.
148+
when(serviceIndex.getProtocols(service)).thenReturn(MapUtils.of(
149+
rpcv2Cbor, null,
150+
json1_0, null,
151+
query, null
152+
));
153+
ShapeId protocol = subject.resolveServiceProtocol(model, service, protocolShapeIds);
154+
// Note: JS customization JSON higher default priority than CBOR.
155+
assertEquals(json1_0, protocol);
156+
}
157+
158+
{
159+
// spec case 4.
160+
when(serviceIndex.getProtocols(service)).thenReturn(MapUtils.of(
161+
json1_0, null,
162+
query, null
163+
));
164+
ShapeId protocol = subject.resolveServiceProtocol(model, service, protocolShapeIds);
165+
assertEquals(json1_0, protocol);
166+
}
167+
168+
{
169+
// spec case 5.
170+
when(serviceIndex.getProtocols(service)).thenReturn(MapUtils.of(
171+
query, null
172+
));
173+
ShapeId protocol = subject.resolveServiceProtocol(model, service, protocolShapeIds);
174+
assertEquals(query, protocol);
175+
}
176+
177+
{
178+
// service override, non-spec
179+
when(serviceIndex.getProtocols(service)).thenReturn(MapUtils.of(
180+
json1_0, null,
181+
json1_1, null,
182+
restJson1, null,
183+
rpcv2Cbor, null,
184+
restXml, null,
185+
query, null,
186+
serviceQuery, null
187+
));
188+
ProtocolPriority.setProtocolPriority(serviceShapeId, List.of(
189+
serviceQuery, rpcv2Cbor, json1_1, restJson1, restXml, query
190+
));
191+
ShapeId protocol = subject.resolveServiceProtocol(model, service, protocolShapeIds);
192+
ProtocolPriority.deleteProtocolPriority(serviceShapeId);
193+
assertEquals(serviceQuery, protocol);
194+
}
195+
196+
{
197+
// global default override
198+
when(serviceIndex.getProtocols(service)).thenReturn(MapUtils.of(
199+
json1_0, null,
200+
json1_1, null,
201+
restJson1, null,
202+
rpcv2Cbor, null,
203+
restXml, null,
204+
query, null,
205+
serviceQuery, null
206+
));
207+
ProtocolPriority.setCustomDefaultProtocolPriority(List.of(
208+
rpcv2Cbor, json1_1, restJson1, restXml, query
209+
));
210+
ShapeId protocol = subject.resolveServiceProtocol(model, service, protocolShapeIds);
211+
ProtocolPriority.deleteCustomDefaultProtocolPriority();
212+
assertEquals(rpcv2Cbor, protocol);
213+
}
214+
}
215+
90216
@Test
91217
public void resolvesSupportProtocols() {
92218
// TODO

yarn.lock

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,7 +2266,7 @@ __metadata:
22662266
languageName: unknown
22672267
linkType: soft
22682268

2269-
"@smithy/core@^2.3.2, @smithy/core@workspace:packages/core":
2269+
"@smithy/core@^2.4.0, @smithy/core@workspace:packages/core":
22702270
version: 0.0.0-use.local
22712271
resolution: "@smithy/core@workspace:packages/core"
22722272
dependencies:
@@ -2590,7 +2590,7 @@ __metadata:
25902590
languageName: unknown
25912591
linkType: soft
25922592

2593-
"@smithy/middleware-retry@^3.0.14, @smithy/middleware-retry@workspace:^, @smithy/middleware-retry@workspace:packages/middleware-retry":
2593+
"@smithy/middleware-retry@^3.0.15, @smithy/middleware-retry@workspace:^, @smithy/middleware-retry@workspace:packages/middleware-retry":
25942594
version: 0.0.0-use.local
25952595
resolution: "@smithy/middleware-retry@workspace:packages/middleware-retry"
25962596
dependencies:
@@ -2784,7 +2784,7 @@ __metadata:
27842784
languageName: unknown
27852785
linkType: soft
27862786

2787-
"@smithy/smithy-client@^3.1.12, @smithy/smithy-client@workspace:^, @smithy/smithy-client@workspace:packages/smithy-client":
2787+
"@smithy/smithy-client@^3.2.0, @smithy/smithy-client@workspace:^, @smithy/smithy-client@workspace:packages/smithy-client":
27882788
version: 0.0.0-use.local
27892789
resolution: "@smithy/smithy-client@workspace:packages/smithy-client"
27902790
dependencies:
@@ -2810,25 +2810,25 @@ __metadata:
28102810
"@aws-crypto/sha256-js": 5.2.0
28112811
"@aws-sdk/types": latest
28122812
"@smithy/config-resolver": ^3.0.5
2813-
"@smithy/core": ^2.3.2
2813+
"@smithy/core": ^2.4.0
28142814
"@smithy/fetch-http-handler": ^3.2.4
28152815
"@smithy/hash-node": ^3.0.3
28162816
"@smithy/invalid-dependency": ^3.0.3
28172817
"@smithy/middleware-content-length": ^3.0.5
2818-
"@smithy/middleware-retry": ^3.0.14
2818+
"@smithy/middleware-retry": ^3.0.15
28192819
"@smithy/middleware-serde": ^3.0.3
28202820
"@smithy/middleware-stack": ^3.0.3
28212821
"@smithy/node-config-provider": ^3.1.4
28222822
"@smithy/node-http-handler": ^3.1.4
28232823
"@smithy/protocol-http": ^4.1.0
2824-
"@smithy/smithy-client": ^3.1.12
2824+
"@smithy/smithy-client": ^3.2.0
28252825
"@smithy/types": ^3.3.0
28262826
"@smithy/url-parser": ^3.0.3
28272827
"@smithy/util-base64": ^3.0.0
28282828
"@smithy/util-body-length-browser": ^3.0.0
28292829
"@smithy/util-body-length-node": ^3.0.0
2830-
"@smithy/util-defaults-mode-browser": ^3.0.14
2831-
"@smithy/util-defaults-mode-node": ^3.0.14
2830+
"@smithy/util-defaults-mode-browser": ^3.0.15
2831+
"@smithy/util-defaults-mode-node": ^3.0.15
28322832
"@smithy/util-middleware": ^3.0.3
28332833
"@smithy/util-retry": ^3.0.3
28342834
"@smithy/util-utf8": ^3.0.0
@@ -2945,7 +2945,7 @@ __metadata:
29452945
languageName: unknown
29462946
linkType: soft
29472947

2948-
"@smithy/util-defaults-mode-browser@^3.0.14, @smithy/util-defaults-mode-browser@workspace:packages/util-defaults-mode-browser":
2948+
"@smithy/util-defaults-mode-browser@^3.0.15, @smithy/util-defaults-mode-browser@workspace:packages/util-defaults-mode-browser":
29492949
version: 0.0.0-use.local
29502950
resolution: "@smithy/util-defaults-mode-browser@workspace:packages/util-defaults-mode-browser"
29512951
dependencies:
@@ -2962,7 +2962,7 @@ __metadata:
29622962
languageName: unknown
29632963
linkType: soft
29642964

2965-
"@smithy/util-defaults-mode-node@^3.0.14, @smithy/util-defaults-mode-node@workspace:packages/util-defaults-mode-node":
2965+
"@smithy/util-defaults-mode-node@^3.0.15, @smithy/util-defaults-mode-node@workspace:packages/util-defaults-mode-node":
29662966
version: 0.0.0-use.local
29672967
resolution: "@smithy/util-defaults-mode-node@workspace:packages/util-defaults-mode-node"
29682968
dependencies:

0 commit comments

Comments
 (0)