Skip to content

Commit

Permalink
Smithy Rules Engine Traits
Browse files Browse the repository at this point in the history
  • Loading branch information
skmcgrail authored and kstich committed Aug 18, 2022
1 parent edfd6cc commit 1c68ab0
Show file tree
Hide file tree
Showing 39 changed files with 2,206 additions and 0 deletions.
6 changes: 6 additions & 0 deletions config/spotbugs/filter.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,10 @@
<Class name="software.amazon.smithy.model.knowledge.PropertyBindingIndex"/>
<Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/>
</Match>

<!-- This is a false positive. The value is guarded behind an Objects.requireNonNull -->
<Match>
<Class name="software.amazon.smithy.rulesengine.traits.ContextIndex"/>
<Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/>
</Match>
</FindBugsFilter>
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ include ":smithy-waiters"
include ":smithy-aws-cloudformation-traits"
include ":smithy-aws-cloudformation"
include ":smithy-validation-model"
include ":smithy-rules-engine"
26 changes: 26 additions & 0 deletions smithy-rules-engine/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2022 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.
*/

description = "Smithy rules engine Language and traits"

ext {
displayName = "Smithy :: Rules Engine"
moduleName = "software.amazon.smithy.rulesengine"
}

dependencies {
api project(":smithy-model")
api project(":smithy-utils")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2022 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.
*/

/**
* Smithy Rules Engine.
*/
@SmithyUnstableApi
package software.amazon.smithy.rulesengine;

import software.amazon.smithy.utils.SmithyUnstableApi;
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2022 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.rulesengine.traits;

import java.util.Objects;
import java.util.Optional;
import software.amazon.smithy.model.shapes.ShapeType;
import software.amazon.smithy.utils.SmithyBuilder;
import software.amazon.smithy.utils.SmithyUnstableApi;
import software.amazon.smithy.utils.ToSmithyBuilder;

/**
* A service client context parameter definition.
*/
@SmithyUnstableApi
public final class ClientContextParamDefinition implements ToSmithyBuilder<ClientContextParamDefinition> {
private final ShapeType type;
private final String documentation;

private ClientContextParamDefinition(Builder builder) {
this.type = SmithyBuilder.requiredState("type", builder.type);
this.documentation = builder.documentation;
}

public static Builder builder() {
return new Builder();
}

public ShapeType getType() {
return type;
}

public Optional<String> getDocumentation() {
return Optional.ofNullable(documentation);
}

public Builder toBuilder() {
return builder()
.type(type)
.documentation(documentation);
}

@Override
public int hashCode() {
return Objects.hash(getType(), getDocumentation());
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ClientContextParamDefinition that = (ClientContextParamDefinition) o;
return getType() == that.getType() && Objects.equals(getDocumentation(), that.getDocumentation());
}

public static final class Builder implements SmithyBuilder<ClientContextParamDefinition> {
private ShapeType type;
private String documentation;

private Builder() {
}

public Builder type(ShapeType type) {
this.type = type;
return this;
}

public Builder documentation(String documentation) {
this.documentation = documentation;
return this;
}

public ClientContextParamDefinition build() {
return new ClientContextParamDefinition(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2022 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.rulesengine.traits;

import java.util.LinkedHashMap;
import java.util.Map;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.NodeMapper;
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.BuilderRef;
import software.amazon.smithy.utils.SmithyBuilder;
import software.amazon.smithy.utils.SmithyUnstableApi;
import software.amazon.smithy.utils.ToSmithyBuilder;

/**
* Indicates that the named rule-set parameters that should be configurable
* on the service client using the specified smithy types.
*/
@SmithyUnstableApi
public final class ClientContextParamsTrait extends AbstractTrait implements ToSmithyBuilder<ClientContextParamsTrait> {
public static final ShapeId ID = ShapeId.from("smithy.rules#clientContextParams");

private final Map<String, ClientContextParamDefinition> parameters;

public ClientContextParamsTrait(Builder builder) {
super(ID, builder.getSourceLocation());
this.parameters = builder.parameters.copy();
}

public static Builder builder() {
return new Builder();
}

public Map<String, ClientContextParamDefinition> getParameters() {
return parameters;
}

@Override
protected Node createNode() {
NodeMapper mapper = new NodeMapper();
return mapper.serialize(this.getParameters()).expectObjectNode();
}

@Override
public SmithyBuilder<ClientContextParamsTrait> toBuilder() {
return builder()
.sourceLocation(getSourceLocation())
.parameters(getParameters());
}

public static final class Provider extends AbstractTrait.Provider {
public Provider() {
super(ID);
}

@Override
public Trait createTrait(ShapeId target, Node value) {
NodeMapper mapper = new NodeMapper();

Map<String, ClientContextParamDefinition> parameters = new LinkedHashMap<>();
value.expectObjectNode().getMembers().forEach((stringNode, node) -> {
parameters.put(stringNode.getValue(), mapper.deserialize(node, ClientContextParamDefinition.class));
});

ClientContextParamsTrait trait = builder()
.parameters(parameters)
.sourceLocation(value)
.build();
trait.setNodeCache(value);
return trait;
}
}

public static final class Builder extends AbstractTraitBuilder<ClientContextParamsTrait, Builder> {
private final BuilderRef<Map<String, ClientContextParamDefinition>> parameters = BuilderRef.forOrderedMap();

private Builder() {
}

public Builder parameters(Map<String, ClientContextParamDefinition> parameters) {
this.parameters.clear();
this.parameters.get().putAll(parameters);
return this;
}

public Builder putParameter(String name, ClientContextParamDefinition definition) {
this.parameters.get().put(name, definition);
return this;
}

public Builder removeParameter(String name) {
this.parameters.get().remove(name);
return this;
}

public Builder clearParameters() {
this.parameters.clear();
return this;
}

@Override
public ClientContextParamsTrait build() {
return new ClientContextParamsTrait(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright 2022 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.rulesengine.traits;

import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.KnowledgeIndex;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.shapes.MemberShape;
import software.amazon.smithy.model.shapes.OperationShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.utils.MapUtils;
import software.amazon.smithy.utils.Pair;
import software.amazon.smithy.utils.SmithyUnstableApi;

/**
* Resolves an indexes the context parameters in the model.
*/
@SmithyUnstableApi
public final class ContextIndex implements KnowledgeIndex {
private final WeakReference<Model> model;

public ContextIndex(Model model) {
this.model = new WeakReference<>(model);
}

public static ContextIndex of(Model model) {
return model.getKnowledge(ContextIndex.class, ContextIndex::new);
}

/**
* Gets the mapping of context parameter names and corresponding {@link ClientContextParamDefinition} to be
* generated on the service client's configuration.
*
* @param service The service shape.
* @return The mapping of context parameter names to {@link ClientContextParamDefinition}.
*/
public Optional<ClientContextParamsTrait> getClientContextParams(Shape service) {
return service.getTrait(ClientContextParamsTrait.class);
}

/**
* Gets the static context parameter names and their {@link StaticContextParamDefinition} to be set for the given
* operation.
*
* @param operation The operation shape.
* @return The mapping of context parameter names to the static {@link Node} value to be set.
*/
public Optional<StaticContextParamsTrait> getStaticContextParams(Shape operation) {
return operation.getTrait(StaticContextParamsTrait.class);
}

/**
* Gets the mapping of {@link MemberShape} to {@link ContextParamTrait} for the operation.
*
* @param operation The operation shape.
* @return The mapping of operation's {@link MemberShape} to {@link ContextParamTrait}.
*/
public Map<MemberShape, ContextParamTrait> getContextParams(Shape operation) {
OperationShape operationShape = operation.asOperationShape()
.orElseThrow(() -> new IllegalArgumentException(operation.toShapeId()
+ " is not an operation shape"));

return getModel().expectShape(operationShape.getInputShape())
.members().stream()
.map(memberShape -> Pair.of(memberShape, memberShape.getTrait(ContextParamTrait.class)))
.filter(pair -> pair.right.isPresent())
.collect(MapUtils.toUnmodifiableMap(pair -> pair.left, pair -> pair.right.get()));
}

private Model getModel() {
return Objects.requireNonNull(model.get(), "The dereferenced WeakReference<Model> is null");
}
}
Loading

0 comments on commit 1c68ab0

Please sign in to comment.