Skip to content

Commit 916a36e

Browse files
committed
Add model bundle API
1 parent 54bbd42 commit 916a36e

File tree

9 files changed

+325
-0
lines changed

9 files changed

+325
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
plugins {
2+
application
3+
id("smithy-java.module-conventions")
4+
id("software.amazon.smithy.gradle.smithy-base")
5+
}
6+
7+
description = "This module implements the model-bundler utility"
8+
9+
extra["displayName"] = "Smithy :: Java :: Model Bundler"
10+
extra["moduleName"] = "software.amazon.smithy.java.modelbundle.api"
11+
12+
dependencies {
13+
smithyBuild(project(":codegen:plugins:types-codegen"))
14+
15+
implementation(project(":core"))
16+
implementation(libs.smithy.model)
17+
api(project(":client:client-auth-api"))
18+
api(project(":client:client-core"))
19+
api(project(":dynamic-schemas"))
20+
}
21+
22+
afterEvaluate {
23+
val typePath = smithy.getPluginProjectionPath(smithy.sourceProjection.get(), "java-type-codegen")
24+
sourceSets {
25+
main {
26+
java {
27+
srcDir(typePath)
28+
include("software/**")
29+
}
30+
resources {
31+
srcDir(typePath)
32+
include("META-INF/**")
33+
}
34+
}
35+
}
36+
}
37+
38+
tasks.named("compileJava") {
39+
dependsOn("smithyBuild")
40+
}
41+
42+
// Needed because sources-jar needs to run after smithy-build is done
43+
tasks.sourcesJar {
44+
mustRunAfter("compileJava")
45+
}
46+
47+
tasks.processResources {
48+
dependsOn("compileJava")
49+
}
50+
51+
sourceSets {
52+
main {
53+
java {
54+
srcDir("model")
55+
}
56+
}
57+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
$version: "2"
2+
3+
namespace software.amazon.smithy.modelbundle.api
4+
5+
structure Bundle {
6+
@required
7+
configType: String
8+
9+
@required
10+
serviceName: String
11+
12+
@required
13+
config: Document
14+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"version": "1.0",
3+
"plugins": {
4+
"java-type-codegen": {
5+
"namespace": "software.amazon.smithy.modelbundle.api",
6+
"headerFile": "license.txt"
7+
}
8+
}
9+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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.modelbundle.api;
7+
8+
import static software.amazon.smithy.modelbundle.api.StaticAuthSchemeResolver.staticScheme;
9+
10+
import software.amazon.smithy.java.client.core.RequestOverrideConfig;
11+
import software.amazon.smithy.java.client.core.auth.identity.IdentityResolver;
12+
import software.amazon.smithy.java.client.core.auth.scheme.AuthScheme;
13+
import software.amazon.smithy.java.client.core.endpoint.EndpointResolver;
14+
import software.amazon.smithy.java.core.serde.document.Document;
15+
import software.amazon.smithy.model.shapes.ShapeId;
16+
17+
/**
18+
* A ConfigProvider is used to parse a bundle of service information (model, auth configuration, endpoints, etc.) and
19+
* configure outgoing client calls as necessary.
20+
*
21+
* <p>Implementations of this interface can define a wrapper type that adds additional parameters to vended MCP tools.
22+
* For example, an AWS auth provider can make a wrapper that adds the region and AWS credential profile name as
23+
* arguments to tools generated for AWS APIs. A wrapper type does not need to be defined if no per-request parameters
24+
* need to be injected.
25+
*
26+
* <p>The ConfigProvider is responsible for configuring outbound client calls with endpoint, identity, and auth resolver
27+
* mechanisms. The default implementation of {@link #adaptConfig(T)} orchestrates the calls to all other ConfigProvider
28+
* APIs and should not be overridden. If an override is needed, the {@code super} method should be called and the
29+
* returned RequestOverrideConfig.Builder should be modified.
30+
*
31+
* @param <T> the type of configuration parsed by this ConfigProvider
32+
*/
33+
public interface ConfigProvider<T> {
34+
/**
35+
* Returns the ShapeId of the wrapper type that this config provider uses.
36+
*
37+
* @return this config provider's wrapper type, or {@code null} if it doesn't use a wrapper
38+
*/
39+
default ShapeId wrapperType() {
40+
return null;
41+
}
42+
43+
/**
44+
* Parses the given document into this ConfigProvider's {@linkplain #wrapperType() wrapper type}.
45+
* If this ConfigProvider has no wrapper type, this method returns null.
46+
*
47+
* @param input the document to parse
48+
* @return the parsed wrapper type
49+
*/
50+
T parse(Document input);
51+
52+
/**
53+
* Returns an identity resolver for the service being called, with optional values provided by the
54+
* parsed wrapper (if present).
55+
*
56+
* @param args the {@linkplain #parse(Document) parsed data wrapper} containing provider-specific arguments
57+
* @return an {@link IdentityResolver} that provides identity information
58+
*/
59+
IdentityResolver<?> identityResolver(T args);
60+
61+
/**
62+
* Returns an auth scheme for the service being called, with optional values provided by the
63+
* parsed wrapper (if present).
64+
*
65+
* @param args the {@linkplain #parse(Document) parsed data wrapper} containing provider-specific arguments
66+
* @return an {@link AuthScheme} that implements the service's required auth mechanism
67+
*/
68+
AuthScheme<?, ?> authScheme(T args);
69+
70+
/**
71+
* Returns an endpoint resolver for the service being called, with optional values provided by the
72+
* parsed wrapper (if present).
73+
*
74+
* @param args the {@linkplain #parse(Document) parsed data wrapper} containing provider-specific arguments
75+
* @return an {@link EndpointResolver} that provides the endpoint to call
76+
*/
77+
EndpointResolver endpointResolver(T args);
78+
79+
/**
80+
* Adapts an outgoing request to use the {@linkplain #authScheme(Object) auth}, {@linkplain #identityResolver(Object) identity},
81+
* and {@linkplain #endpointResolver(Object) endpoint} specified by this ConfigProvider.
82+
*
83+
* @param args the {@linkplain #parse(Document) parsed data wrapper} containing provider-specific arguments
84+
* @return a fully-configured {@link RequestOverrideConfig.Builder} that can be used to make the request
85+
*/
86+
default RequestOverrideConfig.Builder adaptConfig(T args) {
87+
return RequestOverrideConfig.builder()
88+
.authSchemeResolver(StaticAuthSchemeResolver.INSTANCE)
89+
.putSupportedAuthSchemes(staticScheme(authScheme(args)))
90+
.addIdentityResolver(identityResolver(args))
91+
.endpointResolver(endpointResolver(args));
92+
}
93+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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.modelbundle.api;
7+
8+
import software.amazon.smithy.java.core.serde.document.Document;
9+
10+
public interface ConfigProviderFactory {
11+
String identifier();
12+
13+
ConfigProvider<?> createAuthFactory(Document input);
14+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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.modelbundle.api;
7+
8+
import java.util.Collections;
9+
import java.util.HashMap;
10+
import java.util.Map;
11+
import java.util.ServiceLoader;
12+
import software.amazon.smithy.java.core.serde.document.Document;
13+
14+
public final class ConfigProviders {
15+
private static final Map<String, ConfigProviderFactory> PROVIDERS;
16+
17+
static {
18+
Map<String, ConfigProviderFactory> providers = new HashMap<>();
19+
for (var provider : ServiceLoader.load(ConfigProviderFactory.class)) {
20+
providers.put(provider.identifier(), provider);
21+
}
22+
PROVIDERS = Collections.unmodifiableMap(providers);
23+
}
24+
25+
private final Map<String, ConfigProviderFactory> providers;
26+
27+
public ConfigProviders(Builder builder) {
28+
this.providers = builder.providers;
29+
}
30+
31+
public ConfigProvider getProvider(String identifier, Document input) {
32+
var provider = providers.get(identifier);
33+
if (provider == null) {
34+
throw new NullPointerException("no auth provider named " + identifier);
35+
}
36+
37+
return provider.createAuthFactory(input);
38+
}
39+
40+
public static Builder builder() {
41+
return new Builder();
42+
}
43+
44+
public static final class Builder {
45+
private final Map<String, ConfigProviderFactory> providers = new HashMap<>(PROVIDERS);
46+
47+
private Builder() {
48+
49+
}
50+
51+
public Builder addProvider(ConfigProviderFactory provider) {
52+
providers.put(provider.identifier(), provider);
53+
return this;
54+
}
55+
56+
public ConfigProviders build() {
57+
return new ConfigProviders(this);
58+
}
59+
60+
}
61+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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.modelbundle.api;
7+
8+
import java.util.List;
9+
import software.amazon.smithy.java.auth.api.AuthProperties;
10+
import software.amazon.smithy.java.auth.api.Signer;
11+
import software.amazon.smithy.java.auth.api.identity.Identity;
12+
import software.amazon.smithy.java.client.core.auth.identity.IdentityResolver;
13+
import software.amazon.smithy.java.client.core.auth.identity.IdentityResolvers;
14+
import software.amazon.smithy.java.client.core.auth.scheme.AuthScheme;
15+
import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeOption;
16+
import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeResolver;
17+
import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeResolverParams;
18+
import software.amazon.smithy.java.context.Context;
19+
import software.amazon.smithy.model.shapes.ShapeId;
20+
21+
final class StaticAuthSchemeResolver implements AuthSchemeResolver {
22+
static final StaticAuthSchemeResolver INSTANCE = new StaticAuthSchemeResolver();
23+
static final ShapeId CONFIGURED_AUTH = ShapeId.from("modelbundle#configuredAuth");
24+
private static final List<AuthSchemeOption> AUTH_SCHEME_OPTION = List.of(new AuthSchemeOption(CONFIGURED_AUTH));
25+
26+
@Override
27+
public List<AuthSchemeOption> resolveAuthScheme(AuthSchemeResolverParams params) {
28+
return AUTH_SCHEME_OPTION;
29+
}
30+
31+
static <RequestT, IdentityT extends Identity> AuthScheme<RequestT, IdentityT> staticScheme(
32+
AuthScheme<RequestT, IdentityT> actual
33+
) {
34+
return new AuthScheme<>() {
35+
@Override
36+
public ShapeId schemeId() {
37+
return StaticAuthSchemeResolver.CONFIGURED_AUTH;
38+
}
39+
40+
@Override
41+
public Class<RequestT> requestClass() {
42+
return actual.requestClass();
43+
}
44+
45+
@Override
46+
public Class<IdentityT> identityClass() {
47+
return actual.identityClass();
48+
}
49+
50+
@Override
51+
public Signer<RequestT, IdentityT> signer() {
52+
return actual.signer();
53+
}
54+
55+
@Override
56+
public IdentityResolver<IdentityT> identityResolver(IdentityResolvers resolvers) {
57+
return actual.identityResolver(resolvers);
58+
}
59+
60+
@Override
61+
public AuthProperties getSignerProperties(Context context) {
62+
return actual.getSignerProperties(context);
63+
}
64+
65+
@Override
66+
public AuthProperties getIdentityProperties(Context context) {
67+
return actual.getIdentityProperties(context);
68+
}
69+
};
70+
}
71+
}

settings.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,5 @@ include(":mcp")
7979
include(":mcp:mcp-schemas")
8080
include(":server:server-mcp")
8181

82+
83+
include(":model-bundler:bundle-api")

0 commit comments

Comments
 (0)