Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make requiresLength a separate trait #368

Merged
merged 1 commit into from
Apr 13, 2020
Merged
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
64 changes: 41 additions & 23 deletions docs/source/spec/core/stream-traits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ once. This includes both streaming binary data and event streams.
:local:
:backlinks: none


.. _streaming-trait:

-------------------
Expand All @@ -30,29 +31,15 @@ Summary
Trait selector::
``:each(blob, union)``
Value type
``structure``

The value of the ``streaming`` trait is a structure that supports the following
optional members:

.. list-table::
:header-rows: 1
:widths: 10 10 80

* - Property
- Type
- Description
* - requiresLength
- ``boolean``
- Indicates that the stream must have a known size.

In an HTTP-based protocol, for instance, this indicates that the
``content-length`` header must be set.

Shapes targeted by this trait MAY NOT be used outside of top level operation
inputs and operation outputs. Additionally, the ``streaming`` trait is
*structurally exclusive by target*, meaning only a single member of a
structure can target a shape marked as ``streaming``.
Annotation trait
Validation
* ``streaming`` shapes can only be referenced from top-level members
of operation input or output structures.
* Structures that contain a member that targets a ``streaming`` shape
MUST NOT be targeted by other members.
* The ``streaming`` trait is *structurally exclusive by target*, meaning
only a single member of a structure can target a shape marked as
``streaming``.

.. tabs::

Expand All @@ -71,6 +58,37 @@ structure can target a shape marked as ``streaming``.
@streaming
blob StreamingBlob


.. _requiresLength-trait:

------------------------
``requiresLength`` trait
------------------------

Summary
Indicates that the streaming blob MUST be finite and has a known size.

In an HTTP-based protocol, for instance, this trait indicates that the
``Content-Length`` header MUST be sent prior to a client or server
sending the payload of a message. This can be useful for services that
need to determine if a request will be accepted based on its size or
where to store data based on the size of the stream.
Trait selector::
``blob[trait|streaming]``

*A blob shape marked with the streaming trait*
Value type
``structure``

.. tabs::

.. code-tab:: smithy

@streaming
@requiresLength
blob FiniteStreamingBlob


.. _event-streams:

-------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
import software.amazon.smithy.model.traits.ReadonlyTrait;
import software.amazon.smithy.model.traits.ReferencesTrait;
import software.amazon.smithy.model.traits.RequiredTrait;
import software.amazon.smithy.model.traits.RequiresLengthTrait;
import software.amazon.smithy.model.traits.ResourceIdentifierTrait;
import software.amazon.smithy.model.traits.RetryableTrait;
import software.amazon.smithy.model.traits.SensitiveTrait;
Expand Down Expand Up @@ -183,6 +184,7 @@ public final class Prelude {
RangeTrait.ID,
ReadonlyTrait.ID,
ReferencesTrait.ID,
RequiresLengthTrait.ID,
RequiredTrait.ID,
ResourceIdentifierTrait.ID,
RetryableTrait.ID,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2020 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.
*/

package software.amazon.smithy.model.traits;

import software.amazon.smithy.model.SourceLocation;
import software.amazon.smithy.model.shapes.ShapeId;

/**
* Indicates that the streaming blob must be finite and has a known size.
*/
public final class RequiresLengthTrait extends BooleanTrait {
public static final ShapeId ID = ShapeId.from("smithy.api#requiresLength");

public RequiresLengthTrait(SourceLocation sourceLocation) {
super(ID, sourceLocation);
}

public RequiresLengthTrait() {
this(SourceLocation.NONE);
}

public static final class Provider extends BooleanTrait.Provider<RequiresLengthTrait> {
public Provider() {
super(ID, RequiresLengthTrait::new);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,31 @@
package software.amazon.smithy.model.traits;

import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.SourceLocation;
import software.amazon.smithy.model.shapes.MemberShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.utils.ToSmithyBuilder;

/**
* Indicates that the the data stored in the shape is very large and should
* not be stored in memory, or that the size of the data stored in the
* shape is unknown at the start of a request.
*/
public final class StreamingTrait extends AbstractTrait implements ToSmithyBuilder<StreamingTrait> {
public final class StreamingTrait extends BooleanTrait {
public static final ShapeId ID = ShapeId.from("smithy.api#streaming");
private static final String REQUIRES_LENGTH = "requiresLength";

private final boolean requiresLength;

private StreamingTrait(Builder builder) {
super(ID, builder.getSourceLocation());
requiresLength = builder.requiresLength;
public StreamingTrait(SourceLocation sourceLocation) {
super(ID, sourceLocation);
}

/**
* Creates a builder for a streaming trait.
*
* @return Returns the created builder.
*/
public static Builder builder() {
return new Builder();
public StreamingTrait() {
this(SourceLocation.NONE);
}

/**
* @return Returns true if the stream requires a known length.
*/
public boolean getRequiresLength() {
return requiresLength;
public static final class Provider extends BooleanTrait.Provider<StreamingTrait> {
public Provider() {
super(ID, StreamingTrait::new);
}
}

/**
Expand All @@ -75,52 +63,4 @@ public static boolean isEventStream(Shape shape) {
public static boolean isEventStream(Model model, MemberShape member) {
return isEventStream(model.expectShape(member.getTarget()));
}

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

@Override
protected Node createNode() {
return requiresLength ? Node.objectNode().withMember(REQUIRES_LENGTH, true) : Node.objectNode();
}

public static final class Provider implements TraitService {
@Override
public ShapeId getShapeId() {
return ID;
}

@Override
public StreamingTrait createTrait(ShapeId target, Node value) {
ObjectNode node = value.expectObjectNode();
return builder().requiresLength(node.getBooleanMemberOrDefault(REQUIRES_LENGTH)).build();
}
}

/**
* Builds a {@link StreamingTrait} trait.
*/
public static final class Builder extends AbstractTraitBuilder<StreamingTrait, Builder> {
private boolean requiresLength;

private Builder() {}

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

/**
* Indicates if the length of the stream must be known.
*
* @param requiresLength Set to true to require a known length.
* @return Returns the builder.
*/
public Builder requiresLength(boolean requiresLength) {
this.requiresLength = requiresLength;
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ software.amazon.smithy.model.traits.RangeTrait$Provider
software.amazon.smithy.model.traits.ReadonlyTrait$Provider
software.amazon.smithy.model.traits.ReferencesTrait$Provider
software.amazon.smithy.model.traits.RequiredTrait$Provider
software.amazon.smithy.model.traits.RequiresLengthTrait$Provider
software.amazon.smithy.model.traits.ResourceIdentifierTrait$Provider
software.amazon.smithy.model.traits.RetryableTrait$Provider
software.amazon.smithy.model.traits.SensitiveTrait$Provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,16 +315,18 @@ structure sensitive {}
@trait
string since

/// Indicates that the the data stored in the shape is very large and should not
/// Indicates that the data stored in the shape is very large and should not
/// be stored in memory, or that the size of the data stored in the shape is
/// unknown at the start of a request. If the target is a union then the shape
/// represents a stream of events.
@trait(selector: ":each(blob, union)", structurallyExclusive: "target")
@tags(["diff.error.const"])
structure streaming {
/// Indicates that the stream must have a known size.
requiresLength: Boolean,
}
structure streaming {}

/// Indicates that the streaming blob must be finite and has a known size.
@trait(selector: "blob[trait|streaming]")
@tags(["diff.error.const"])
structure requiresLength {}

/// Tags a shape with arbitrary tag names that can be used to filter and
/// group shapes in the model.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ public void loadsTrait() {

assertTrue(trait.isPresent());
assertThat(trait.get(), instanceOf(StreamingTrait.class));
assertThat(trait.get().toNode(), equalTo(Node.objectNode()));
assertThat(trait.get().toNode(), equalTo(Node.from(true)));
}
}