diff --git a/DEPENDENCIES b/DEPENDENCIES index 7cf5903b5..bea447e5c 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -231,6 +231,7 @@ maven/mavencentral/org.codehaus.plexus/plexus-container-default/2.1.0, Apache-2. maven/mavencentral/org.codehaus.plexus/plexus-utils/3.1.1, , approved, CQ16492 maven/mavencentral/org.codehaus.plexus/plexus-utils/3.3.0, , approved, CQ21066 maven/mavencentral/org.eclipse.angus/angus-activation/1.0.0, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.angus +maven/mavencentral/org.eclipse.edc/api-core/0.8.2-SNAPSHOT, Apache-2.0, approved, technology.edc maven/mavencentral/org.eclipse.edc/api-observability/0.8.2-SNAPSHOT, Apache-2.0, approved, technology.edc maven/mavencentral/org.eclipse.edc/asset-spi/0.8.2-SNAPSHOT, Apache-2.0, approved, technology.edc maven/mavencentral/org.eclipse.edc/auth-spi/0.8.2-SNAPSHOT, Apache-2.0, approved, technology.edc @@ -296,6 +297,7 @@ maven/mavencentral/org.eclipse.edc/validator-lib/0.8.2-SNAPSHOT, Apache-2.0, app maven/mavencentral/org.eclipse.edc/validator-spi/0.8.2-SNAPSHOT, Apache-2.0, approved, technology.edc maven/mavencentral/org.eclipse.edc/verifiable-credentials-spi/0.8.2-SNAPSHOT, Apache-2.0, approved, technology.edc maven/mavencentral/org.eclipse.edc/verifiable-credentials/0.8.2-SNAPSHOT, Apache-2.0, approved, technology.edc +maven/mavencentral/org.eclipse.edc/version-api/0.8.2-SNAPSHOT, Apache-2.0, approved, technology.edc maven/mavencentral/org.eclipse.edc/web-spi/0.8.2-SNAPSHOT, Apache-2.0, approved, technology.edc maven/mavencentral/org.eclipse.jetty.toolchain/jetty-jakarta-servlet-api/5.0.2, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty.toolchain/jetty-jakarta-websocket-api/2.0.0, EPL-2.0 OR Apache-2.0, approved, rt.jetty diff --git a/core/presentation-api/build.gradle.kts b/core/presentation-api/build.gradle.kts index fee3c3135..887e16126 100644 --- a/core/presentation-api/build.gradle.kts +++ b/core/presentation-api/build.gradle.kts @@ -40,6 +40,6 @@ dependencies { edcBuild { swagger { - apiGroup.set("ih-resolution-api") + apiGroup.set("presentation-api") } } \ No newline at end of file diff --git a/core/presentation-api/src/main/java/org/eclipse/edc/identityhub/api/PresentationApiExtension.java b/core/presentation-api/src/main/java/org/eclipse/edc/identityhub/api/PresentationApiExtension.java index 2f0d8ca03..72173c1ec 100644 --- a/core/presentation-api/src/main/java/org/eclipse/edc/identityhub/api/PresentationApiExtension.java +++ b/core/presentation-api/src/main/java/org/eclipse/edc/identityhub/api/PresentationApiExtension.java @@ -14,6 +14,7 @@ package org.eclipse.edc.identityhub.api; +import com.fasterxml.jackson.databind.DeserializationFeature; import org.eclipse.edc.iam.identitytrust.spi.model.PresentationQueryMessage; import org.eclipse.edc.iam.identitytrust.transform.from.JsonObjectFromPresentationResponseMessageTransformer; import org.eclipse.edc.iam.identitytrust.transform.to.JsonObjectToPresentationQueryTransformer; @@ -26,8 +27,11 @@ import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.EdcException; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.apiversion.ApiVersionService; +import org.eclipse.edc.spi.system.apiversion.VersionRecord; import org.eclipse.edc.spi.types.TypeManager; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.eclipse.edc.transform.transformer.edc.to.JsonValueToGenericTypeTransformer; @@ -36,8 +40,12 @@ import org.eclipse.edc.web.jersey.providers.jsonld.ObjectMapperProvider; import org.eclipse.edc.web.spi.WebService; +import java.io.IOException; +import java.util.stream.Stream; + import static org.eclipse.edc.iam.identitytrust.spi.DcpConstants.DCP_CONTEXT_URL; import static org.eclipse.edc.identityhub.api.PresentationApiExtension.NAME; +import static org.eclipse.edc.identityhub.spi.IdentityHubApiContext.PRESENTATION; import static org.eclipse.edc.spi.constants.CoreConstants.JSON_LD; @Extension(value = NAME) @@ -45,7 +53,7 @@ public class PresentationApiExtension implements ServiceExtension { public static final String NAME = "Presentation API Extension"; public static final String RESOLUTION_SCOPE = "resolution-scope"; - public static final String RESOLUTION_CONTEXT = "resolution"; + private static final String API_VERSION_JSON_FILE = "presentation-api-version.json"; @Inject private TypeTransformerRegistry typeTransformer; @Inject @@ -64,6 +72,8 @@ public class PresentationApiExtension implements ServiceExtension { private TypeManager typeManager; @Inject private ParticipantContextService participantContextService; + @Inject + private ApiVersionService apiVersionService; @Override public String name() { @@ -79,9 +89,9 @@ public void initialize(ServiceExtensionContext context) { var controller = new PresentationApiController(validatorRegistry, typeTransformer, credentialResolver, accessTokenVerifier, verifiablePresentationService, context.getMonitor(), participantContextService); var jsonLdMapper = typeManager.getMapper(JSON_LD); - webService.registerResource(RESOLUTION_CONTEXT, new ObjectMapperProvider(jsonLdMapper)); - webService.registerResource(RESOLUTION_CONTEXT, new JerseyJsonLdInterceptor(jsonLd, jsonLdMapper, RESOLUTION_SCOPE)); - webService.registerResource(RESOLUTION_CONTEXT, controller); + webService.registerResource(PRESENTATION, new ObjectMapperProvider(jsonLdMapper)); + webService.registerResource(PRESENTATION, new JerseyJsonLdInterceptor(jsonLd, jsonLdMapper, RESOLUTION_SCOPE)); + webService.registerResource(PRESENTATION, controller); jsonLd.registerContext(DCP_CONTEXT_URL, RESOLUTION_SCOPE); @@ -89,7 +99,22 @@ public void initialize(ServiceExtensionContext context) { typeTransformer.register(new JsonObjectToPresentationQueryTransformer(jsonLdMapper)); typeTransformer.register(new JsonValueToGenericTypeTransformer(jsonLdMapper)); typeTransformer.register(new JsonObjectFromPresentationResponseMessageTransformer()); + + registerVersionInfo(getClass().getClassLoader()); } + private void registerVersionInfo(ClassLoader resourceClassLoader) { + try (var versionContent = resourceClassLoader.getResourceAsStream(API_VERSION_JSON_FILE)) { + if (versionContent == null) { + throw new EdcException("Version file not found or not readable."); + } + Stream.of(typeManager.getMapper() + .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + .readValue(versionContent, VersionRecord[].class)) + .forEach(vr -> apiVersionService.addRecord("presentation", vr)); + } catch (IOException e) { + throw new EdcException(e); + } + } } diff --git a/core/presentation-api/src/main/resources/presentation-api-version.json b/core/presentation-api/src/main/resources/presentation-api-version.json new file mode 100644 index 000000000..3b1fa47fb --- /dev/null +++ b/core/presentation-api/src/main/resources/presentation-api-version.json @@ -0,0 +1,8 @@ +[ + { + "version": "1.0.0", + "urlPath": "/v1", + "lastUpdated": "2024-08-22T09:20:00Z", + "maturity": "stable" + } +] \ No newline at end of file diff --git a/extensions/api/identity-api/api-configuration/src/main/java/org/eclipse/edc/identityhub/api/configuration/IdentityApiConfigurationExtension.java b/extensions/api/identity-api/api-configuration/src/main/java/org/eclipse/edc/identityhub/api/configuration/IdentityApiConfigurationExtension.java index 1d13f4a0b..5f2e2b0ed 100644 --- a/extensions/api/identity-api/api-configuration/src/main/java/org/eclipse/edc/identityhub/api/configuration/IdentityApiConfigurationExtension.java +++ b/extensions/api/identity-api/api-configuration/src/main/java/org/eclipse/edc/identityhub/api/configuration/IdentityApiConfigurationExtension.java @@ -14,21 +14,30 @@ package org.eclipse.edc.identityhub.api.configuration; +import com.fasterxml.jackson.databind.DeserializationFeature; import jakarta.ws.rs.core.SecurityContext; import org.eclipse.edc.identityhub.spi.AuthorizationService; +import org.eclipse.edc.identityhub.spi.IdentityHubApiContext; import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantResource; import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Provider; +import org.eclipse.edc.spi.EdcException; import org.eclipse.edc.spi.result.ServiceResult; import org.eclipse.edc.spi.security.Vault; import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.apiversion.ApiVersionService; +import org.eclipse.edc.spi.system.apiversion.VersionRecord; +import org.eclipse.edc.spi.types.TypeManager; import org.eclipse.edc.web.spi.WebServer; import org.eclipse.edc.web.spi.WebService; import org.eclipse.edc.web.spi.configuration.WebServiceConfigurer; +import java.io.IOException; import java.util.function.Function; +import java.util.stream.Stream; import static org.eclipse.edc.identityhub.api.configuration.IdentityApiConfigurationExtension.NAME; @@ -37,6 +46,7 @@ public class IdentityApiConfigurationExtension implements ServiceExtension { public static final String NAME = "Identity API Extension"; + private static final String API_VERSION_JSON_FILE = "identity-api-version.json"; @Inject private WebService webService; @Inject @@ -47,6 +57,11 @@ public class IdentityApiConfigurationExtension implements ServiceExtension { private WebServer webServer; @Inject private Vault vault; + @Inject + private TypeManager typeManager; + + @Inject + private ApiVersionService apiVersionService; @Override public String name() { @@ -54,11 +69,29 @@ public String name() { } + @Override + public void initialize(ServiceExtensionContext context) { + registerVersionInfo(getClass().getClassLoader()); + } + @Provider(isDefault = true) public AuthorizationService authorizationService() { return new AllowAllAuthorizationService(); } + private void registerVersionInfo(ClassLoader resourceClassLoader) { + try (var versionContent = resourceClassLoader.getResourceAsStream(API_VERSION_JSON_FILE)) { + if (versionContent == null) { + throw new EdcException("Version file not found or not readable."); + } + Stream.of(typeManager.getMapper() + .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + .readValue(versionContent, VersionRecord[].class)) + .forEach(vr -> apiVersionService.addRecord(IdentityHubApiContext.IDENTITY, vr)); + } catch (IOException e) { + throw new EdcException(e); + } + } private static class AllowAllAuthorizationService implements AuthorizationService { @Override diff --git a/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json b/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json new file mode 100644 index 000000000..e1cd4bdad --- /dev/null +++ b/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json @@ -0,0 +1,8 @@ +[ + { + "version": "1.0.0-alpha", + "urlPath": "/v1alpha", + "lastUpdated": "2024-08-22T09:20:00Z", + "maturity": null + } +] \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e1cfc733a..00f25c4c1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,6 +57,8 @@ edc-ext-transaction-local = { module = "org.eclipse.edc:transaction-local", vers edc-testfixtures-managementapi = { module = "org.eclipse.edc:management-api-test-fixtures", version.ref = "edc" } edc-sql-pool = { module = "org.eclipse.edc:sql-pool-apache-commons", version.ref = "edc" } edc-sql-bootstrapper = { module = "org.eclipse.edc:sql-bootstrapper", version.ref = "edc" } +edc-api-version = { module = "org.eclipse.edc:version-api", version.ref = "edc" } + # EDC libs edc-lib-keys = { "module" = "org.eclipse.edc:keys-lib", version.ref = "edc" } diff --git a/launcher/build.gradle.kts b/launcher/build.gradle.kts index 992699d5c..b0b058a49 100644 --- a/launcher/build.gradle.kts +++ b/launcher/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { runtimeOnly(project(":extensions:api:identityhub-api-authorization")) runtimeOnly(libs.edc.identity.did.core) runtimeOnly(libs.edc.core.token) + runtimeOnly(libs.edc.api.version) runtimeOnly(libs.edc.identity.did.web) runtimeOnly(libs.bundles.connector) diff --git a/resources/openapi/identity-api.version b/resources/openapi/identity-api.version new file mode 100644 index 000000000..a071f2c3c --- /dev/null +++ b/resources/openapi/identity-api.version @@ -0,0 +1 @@ +extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json \ No newline at end of file diff --git a/resources/openapi/presentation-api.version b/resources/openapi/presentation-api.version new file mode 100644 index 000000000..0d7896eb5 --- /dev/null +++ b/resources/openapi/presentation-api.version @@ -0,0 +1 @@ +core/presentation-api/src/main/resources/presentation-api-version.json \ No newline at end of file diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/IdentityHubApiContext.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/IdentityHubApiContext.java index 7e39e91b6..a205975a8 100644 --- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/IdentityHubApiContext.java +++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/IdentityHubApiContext.java @@ -17,4 +17,5 @@ public interface IdentityHubApiContext { String IDENTITY = "identity"; String IH_DID = "did"; + String PRESENTATION = "resolution"; // should be "presentation", but this would break config }