Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: smithy-lang/smithy
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 92af1bedda5fa64fe6ee75255e5e9dbd16364905
Choose a base ref
..
head repository: smithy-lang/smithy
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ce42033705beca33b4cc530740d94be45ba1b3c4
Choose a head ref
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.rulesengine.language;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.function.Function;
import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.FunctionDefinition;
import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.FunctionNode;
import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.LibraryFunction;
import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter;
import software.amazon.smithy.rulesengine.validators.AuthSchemeValidator;
import software.amazon.smithy.utils.SmithyInternalApi;

/**
* Provides access to endpoint components loaded through {@link EndpointRuleSetExtension}s.
*/
@SmithyInternalApi
public interface EndpointComponentFactory {

/**
* Returns true if a built-in of the provided name has been registered.
*
* @param name the name of the built-in to check for.
* @return true if the built-in is present, false otherwise.
*/
boolean hasBuiltIn(String name);

/**
* Gets the built-in names as a joined string.
*
* @return a string of the built-in names.
*/
String getKeyString();

/**
* Creates a {@link LibraryFunction} factory function using the loaded function definitions.
*
* @return the created factory.
*/
Function<FunctionNode, Optional<LibraryFunction>> createFunctionFactory();

/**
* Gets loaded authentication scheme validators.
*
* @return a list of {@link AuthSchemeValidator}s.
*/
List<AuthSchemeValidator> getAuthSchemeValidators();

static EndpointComponentFactory createServiceFactory(
Map<String, Parameter> builtIns,
Map<String, FunctionDefinition> libraryFunctions,
List<AuthSchemeValidator> authSchemeValidators
) {
return new EndpointComponentFactory() {
@Override
public boolean hasBuiltIn(String name) {
return builtIns.containsKey(name);
}

@Override
public String getKeyString() {
return String.join(", ", builtIns.keySet());
}

@Override
public Function<FunctionNode, Optional<LibraryFunction>> createFunctionFactory() {
return node -> {
if (libraryFunctions.containsKey(node.getName())) {
return Optional.of(libraryFunctions.get(node.getName()).createFunction(node));
}
return Optional.empty();
};
}

@Override
public List<AuthSchemeValidator> getAuthSchemeValidators() {
return authSchemeValidators;
}
};
}

static EndpointComponentFactory createServiceFactory(ClassLoader classLoader) {
Map<String, Parameter> builtIns = new HashMap<>();
Map<String, FunctionDefinition> libraryFunctions = new HashMap<>();
List<AuthSchemeValidator> authSchemeValidators = new ArrayList<>();
for (EndpointRuleSetExtension extension : ServiceLoader.load(EndpointRuleSetExtension.class, classLoader)) {
String name;
for (Parameter builtIn : extension.getBuiltIns()) {
name = builtIn.getBuiltIn().get();
if (builtIns.containsKey(name)) {
throw new RuntimeException("Attempted to load a duplicate built-in parameter: " + name);
}
builtIns.put(name, builtIn);
}

for (FunctionDefinition functionDefinition : extension.getLibraryFunctions()) {
name = functionDefinition.getId();
if (libraryFunctions.containsKey(name)) {
throw new RuntimeException("Attempted to load a duplicate library function: " + name);
}
libraryFunctions.put(name, functionDefinition);
}

authSchemeValidators.addAll(extension.getAuthSchemeValidators());
}

return createServiceFactory(builtIns, libraryFunctions, authSchemeValidators);
}
}
Original file line number Diff line number Diff line change
@@ -7,14 +7,10 @@

import static software.amazon.smithy.rulesengine.language.error.RuleError.context;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.function.Function;
import software.amazon.smithy.model.FromSourceLocation;
import software.amazon.smithy.model.SourceLocation;
@@ -26,16 +22,15 @@
import software.amazon.smithy.rulesengine.language.evaluation.Scope;
import software.amazon.smithy.rulesengine.language.evaluation.TypeCheck;
import software.amazon.smithy.rulesengine.language.evaluation.type.Type;
import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.FunctionDefinition;
import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.FunctionNode;
import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.LibraryFunction;
import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter;
import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters;
import software.amazon.smithy.rulesengine.language.syntax.rule.EndpointRule;
import software.amazon.smithy.rulesengine.language.syntax.rule.Rule;
import software.amazon.smithy.rulesengine.validators.AuthSchemeValidator;
import software.amazon.smithy.utils.BuilderRef;
import software.amazon.smithy.utils.SmithyBuilder;
import software.amazon.smithy.utils.SmithyInternalApi;
import software.amazon.smithy.utils.SmithyUnstableApi;
import software.amazon.smithy.utils.StringUtils;
import software.amazon.smithy.utils.ToSmithyBuilder;
@@ -50,37 +45,9 @@ public final class EndpointRuleSet implements FromSourceLocation, ToNode, ToSmit
private static final String PARAMETERS = "parameters";
private static final String RULES = "rules";

private static final Map<String, Parameter> BUILT_INS = new HashMap<>();
private static final Map<String, FunctionDefinition> FUNCTIONS = new HashMap<>();
private static final List<AuthSchemeValidator> AUTH_SCHEME_VALIDATORS = new ArrayList<>();

static {
// Provide an explicit classloader, as the thread's classloader may be different in cases
// where a model is loaded in extraneous contexts, like a build tool.
// TODO Change how the classloader is configured.
for (EndpointRuleSetExtension extension : ServiceLoader.load(EndpointRuleSetExtension.class,
EndpointRuleSet.class.getClassLoader())
) {
System.out.println(extension.getClass().getCanonicalName());
String name;
for (Parameter builtIn : extension.getBuiltIns()) {
name = builtIn.getBuiltIn().get();
if (BUILT_INS.containsKey(name)) {
throw new RuntimeException("Attempted to load a duplicate built-in parameter: " + name);
}
BUILT_INS.put(name, builtIn);
}

for (FunctionDefinition functionDefinition : extension.getLibraryFunctions()) {
name = functionDefinition.getId();
if (FUNCTIONS.containsKey(name)) {
throw new RuntimeException("Attempted to load a duplicate library function: " + name);
}
FUNCTIONS.put(name, functionDefinition);
}

AUTH_SCHEME_VALIDATORS.addAll(extension.getAuthSchemeValidators());
}
private static final class LazyEndpointComponentFactoryHolder {
static final EndpointComponentFactory INSTANCE = EndpointComponentFactory.createServiceFactory(
EndpointRuleSet.class.getClassLoader());
}

private final Parameters parameters;
@@ -228,40 +195,39 @@ public String toString() {
* @param name the name of the built-in to check for.
* @return true if the built-in is present, false otherwise.
*/
@SmithyInternalApi
public static boolean hasBuiltIn(String name) {
return BUILT_INS.containsKey(name);
return LazyEndpointComponentFactoryHolder.INSTANCE.hasBuiltIn(name);
}

/**
* Gets the built-in names as a joined string.
*
* @return a string of the built-in names.
*/
@SmithyInternalApi
public static String getKeyString() {
return String.join(", ", BUILT_INS.keySet());
return LazyEndpointComponentFactoryHolder.INSTANCE.getKeyString();
}

/**
* Creates a {@link LibraryFunction} factory function using the loaded function definitions.
*
* @return the created factory.
*/
@SmithyInternalApi
public static Function<FunctionNode, Optional<LibraryFunction>> createFunctionFactory() {
return node -> {
if (FUNCTIONS.containsKey(node.getName())) {
return Optional.of(FUNCTIONS.get(node.getName()).createFunction(node));
}
return Optional.empty();
};
return LazyEndpointComponentFactoryHolder.INSTANCE.createFunctionFactory();
}

/**
* Gets loaded authentication scheme validators.
*
* @return a list of {@link AuthSchemeValidator}s.
*/
@SmithyInternalApi
public static List<AuthSchemeValidator> getAuthSchemeValidators() {
return AUTH_SCHEME_VALIDATORS;
return LazyEndpointComponentFactoryHolder.INSTANCE.getAuthSchemeValidators();
}

/**