Skip to content

Commit

Permalink
Move to CBOR trait from configured formats
Browse files Browse the repository at this point in the history
This commit refactors the trait implementation to be specific to the
CBOR wire format instead of taking a collection of possible wire
formats, simplifying the process of resolving the protocol to use
for generated code.

It also moves the package to `smithy-protocol-traits`, removing the
pluralization on `protocols`.
  • Loading branch information
kstich committed Mar 11, 2024
1 parent a043f24 commit f800486
Show file tree
Hide file tree
Showing 24 changed files with 301 additions and 459 deletions.
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ include ":smithy-smoke-test-traits"
include ":smithy-syntax"
include ":smithy-aws-endpoints"
include ":smithy-aws-smoke-test-model"
include ":smithy-protocols-traits"
include ":smithy-protocol-traits"
File renamed without changes.
16 changes: 16 additions & 0 deletions smithy-protocol-traits/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

description = "This module provides the implementation of protocol traits for Smithy."

ext {
displayName = "Smithy :: Protocol Traits"
moduleName = "software.amazon.smithy.protocol.traits"
}

dependencies {
api project(":smithy-utils")
api project(":smithy-model")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.protocol.traits;

import java.util.ArrayList;
import java.util.List;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.traits.AbstractTrait;
import software.amazon.smithy.model.traits.AbstractTraitBuilder;
import software.amazon.smithy.model.traits.Trait;
import software.amazon.smithy.utils.ListUtils;
import software.amazon.smithy.utils.ToSmithyBuilder;

public final class Rpcv2CborTrait extends AbstractTrait implements ToSmithyBuilder<Rpcv2CborTrait> {

public static final ShapeId ID = ShapeId.from("smithy.protocols#rpcv2Cbor");

private static final String HTTP = "http";
private static final String EVENT_STREAM_HTTP = "eventStreamHttp";

private final List<String> http;
private final List<String> eventStreamHttp;

private Rpcv2CborTrait(Builder builder) {
super(ID, builder.getSourceLocation());
http = ListUtils.copyOf(builder.http);
eventStreamHttp = ListUtils.copyOf(builder.eventStreamHttp);
}

/**
* Creates a new {@code Builder}.
*/
public static Builder builder() {
return new Builder();
}

/**
* Updates the builder from a Node.
*
* @param node Node object that must be a valid {@code ObjectNode}.
* @return Returns the updated builder.
*/
public static Rpcv2CborTrait fromNode(Node node) {
Builder builder = builder().sourceLocation(node);
ObjectNode objectNode = node.expectObjectNode();
objectNode.getArrayMember(HTTP).map(values -> Node.loadArrayOfString(HTTP, values))
.ifPresent(builder::http);
objectNode.getArrayMember(EVENT_STREAM_HTTP).map(values -> Node.loadArrayOfString(EVENT_STREAM_HTTP, values))
.ifPresent(builder::eventStreamHttp);
return builder.build();
}

/**
* Gets the priority ordered list of supported HTTP protocol versions.
*
* @return Returns the supported HTTP protocol versions.
*/
public List<String> getHttp() {
return http;
}

/**
* Gets the priority ordered list of supported HTTP protocol versions that are required when
* using event streams.
*
* @return Returns the supported event stream HTTP protocol versions.
*/
public List<String> getEventStreamHttp() {
return eventStreamHttp;
}

@Override
protected Node createNode() {
ObjectNode.Builder builder = Node.objectNodeBuilder().sourceLocation(getSourceLocation());
if (!getHttp().isEmpty()) {
builder.withMember(HTTP, Node.fromStrings(getHttp()));
}
if (!getEventStreamHttp().isEmpty()) {
builder.withMember(EVENT_STREAM_HTTP, Node.fromStrings(getEventStreamHttp()));
}
return builder.build();
}

@Override
public Builder toBuilder() {
return builder().http(http).eventStreamHttp(eventStreamHttp);
}

/**
* Builder for creating a {@code Rpcv2CborTrait}.
*/
public static final class Builder extends AbstractTraitBuilder<Rpcv2CborTrait, Builder> {

private final List<String> http = new ArrayList<>();
private final List<String> eventStreamHttp = new ArrayList<>();

@Override
public Rpcv2CborTrait build() {
return new Rpcv2CborTrait(this);
}

/**
* Sets the list of supported HTTP protocols.
*
* @param http HTTP protocols to set and replace.
* @return Returns the builder.
*/
public Builder http(List<String> http) {
this.http.clear();
this.http.addAll(http);
return this;
}

/**
* Sets the list of supported event stream HTTP protocols.
*
* @param eventStreamHttp Event stream HTTP protocols to set and replace.
* @return Returns the builder.
*/
public Builder eventStreamHttp(List<String> eventStreamHttp) {
this.eventStreamHttp.clear();
this.eventStreamHttp.addAll(eventStreamHttp);
return this;
}
}

/**
* Implements the {@code AbstractTrait.Provider}.
*/
public static final class Provider extends AbstractTrait.Provider {

public Provider() {
super(ID);
}

@Override
public Trait createTrait(ShapeId target, Node value) {
Rpcv2CborTrait result = fromNode(value);
result.setNodeCache(value);
return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.protocol.traits;

import java.util.ArrayList;
import java.util.List;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.validation.AbstractValidator;
import software.amazon.smithy.model.validation.ValidationEvent;
import software.amazon.smithy.utils.SmithyInternalApi;

/**
* Validates models implementing the {@code Rpcv2CborTrait} against its constraints by:
*
* - Ensuring that every entry in {@code eventStreamHttp} also appears in the {@code http} property
* of a protocol trait.
*/
@SmithyInternalApi
public final class Rpcv2CborTraitValidator extends AbstractValidator {

@Override
public List<ValidationEvent> validate(Model model) {
List<ValidationEvent> events = new ArrayList<>();
for (ServiceShape serviceShape : model.getServiceShapesWithTrait(Rpcv2CborTrait.class)) {
Rpcv2CborTrait protocolTrait = serviceShape.expectTrait(Rpcv2CborTrait.class);

List<String> invalid = new ArrayList<>(protocolTrait.getEventStreamHttp());
invalid.removeAll(protocolTrait.getHttp());
if (!invalid.isEmpty()) {
events.add(error(serviceShape, protocolTrait,
String.format("The following values of the `eventStreamHttp` property do "
+ "not also appear in the `http` property of the %s protocol "
+ "trait: %s", protocolTrait.toShapeId(), invalid)));
}
}
return events;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Defines protocols for Smithy.
*/
@SmithyUnstableApi
package software.amazon.smithy.protocol.traits;

import software.amazon.smithy.utils.SmithyUnstableApi;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
software.amazon.smithy.protocol.traits.Rpcv2CborTrait$Provider
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
software.amazon.smithy.protocol.traits.Rpcv2CborTraitValidator
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,26 @@ $version: "2.0"

namespace smithy.protocols

use smithy.api#httpError
use smithy.api#cors
use smithy.api#endpoint
use smithy.api#hostLabel
use smithy.api#httpError

/// An RPC protocol with support for multiple wire formats.
/// An RPC-based protocol that serializes CBOR payloads.
@trait(selector: "service")
@protocolDefinition(traits: [
httpError
cors
endpoint
hostLabel
httpError
])
structure rpcv2 {
structure rpcv2Cbor {
/// Priority ordered list of supported HTTP protocol versions.
http: StringList

/// Priority ordered list of supported HTTP protocol versions
/// that are required when using event streams.
eventStreamHttp: StringList

/// Priority ordered list of supported wire formats.
@required
format: StringList
}

/// A list of String shapes.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.protocol.traits;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.traits.Trait;
import software.amazon.smithy.model.traits.TraitFactory;
import java.util.Optional;

public class Rpcv2CborTraitTest {

@Test
public void loadsTraitWithDefaults() {
Node node = Node.objectNode();
TraitFactory provider = TraitFactory.createServiceFactory();
Optional<Trait> trait = provider.createTrait(Rpcv2CborTrait.ID, ShapeId.from("ns.foo#foo"), node);

Assertions.assertTrue(trait.isPresent());
Assertions.assertTrue(trait.get() instanceof Rpcv2CborTrait);
Rpcv2CborTrait smithyRpcV2Trait = (Rpcv2CborTrait) trait.get();
Assertions.assertEquals(smithyRpcV2Trait.toNode(), node);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
/*
* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
* in compliance with the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.protocols.traits;
package software.amazon.smithy.protocol.traits;

import java.util.concurrent.Callable;
import java.util.stream.Stream;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[ERROR] smithy.example#InvalidService1: The following values of the `eventStreamHttp` property do not also appear in the `http` property of the smithy.protocols#rpcv2 protocol trait: [http/1.1] | Rpcv2Trait
[ERROR] smithy.example#InvalidService2: The following values of the `eventStreamHttp` property do not also appear in the `http` property of the smithy.protocols#rpcv2 protocol trait: [http/1.1] | Rpcv2Trait
[ERROR] smithy.example#InvalidService3: The following values of the `eventStreamHttp` property do not also appear in the `http` property of the smithy.protocols#rpcv2 protocol trait: [http/1.1, h2c] | Rpcv2Trait
[ERROR] smithy.example#InvalidService1: The following values of the `eventStreamHttp` property do not also appear in the `http` property of the smithy.protocols#rpcv2Cbor protocol trait: [http/1.1] | Rpcv2CborTrait
[ERROR] smithy.example#InvalidService2: The following values of the `eventStreamHttp` property do not also appear in the `http` property of the smithy.protocols#rpcv2Cbor protocol trait: [http/1.1] | Rpcv2CborTrait
[ERROR] smithy.example#InvalidService3: The following values of the `eventStreamHttp` property do not also appear in the `http` property of the smithy.protocols#rpcv2Cbor protocol trait: [http/1.1, h2c] | Rpcv2CborTrait
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
$version: "2.0"

namespace smithy.example

use smithy.protocols#rpcv2Cbor

@rpcv2Cbor(http: ["h2", "http/1.1"], eventStreamHttp: ["h2"])
service ValidService1 {
version: "2023-02-10"
}

@rpcv2Cbor(http: ["h2"], eventStreamHttp: ["h2"])
service ValidService2 {
version: "2023-02-10"
}

@rpcv2Cbor(http: [], eventStreamHttp: [])
service ValidService3 {
version: "2023-02-10"
}

@rpcv2Cbor(http: ["http/1.1"], eventStreamHttp: [])
service ValidService4 {
version: "2023-02-10"
}

@rpcv2Cbor(eventStreamHttp: ["http/1.1"])
service InvalidService1 {
version: "2023-02-10"
}

@rpcv2Cbor(http: ["h2"], eventStreamHttp: ["http/1.1"])
service InvalidService2 {
version: "2023-02-10"
}

@rpcv2Cbor(http: ["h2"], eventStreamHttp: ["h2", "http/1.1", "h2c"])
service InvalidService3 {
version: "2023-02-10"
}
26 changes: 0 additions & 26 deletions smithy-protocols-traits/build.gradle

This file was deleted.

Loading

0 comments on commit f800486

Please sign in to comment.