-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature/vocabulary-api-extensions' into 'develop'
vocabulary api management See merge request upm-inesdata/inesdata-connector!13
- Loading branch information
Showing
35 changed files
with
1,511 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Vocabulary API | ||
|
||
Provides a management API for work with vocabularies. This API expands the functionality of the control-plane management API to be able to handle Vocabulary entities. | ||
|
||
|
||
## Vocabulary entity | ||
|
||
An example of a Vocabulary entity is shown below. | ||
|
||
``` | ||
{ | ||
"@context": { | ||
"@vocab": "https://w3id.org/edc/v0.0.1/ns/" | ||
}, | ||
"@id": "vocabularyId", | ||
"name": "Vocabulary name", | ||
"jsonSchema": "{ \"title\": \"vocabulary\", \"type\": \"object\", \"properties\": { \"name\": { \"type\": \"string\", \"title\": \"Name\" }, \"keyword\": { \"type\": \"array\", \"title\": \"Keywords\", \"items\": { \"type\": \"string\" } } }, \"required\": [ \"name\" ] }" | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
plugins { | ||
`java-library` | ||
id("com.gmv.inesdata.edc-application") | ||
} | ||
|
||
dependencies { | ||
api(project(":spi:vocabulary-spi")) | ||
api(libs.edc.spi.core) | ||
implementation(libs.edc.spi.transform) | ||
implementation(libs.edc.web.spi) | ||
|
||
implementation(libs.edc.connector.core) | ||
implementation(libs.edc.api.core) | ||
implementation(libs.edc.lib.util) | ||
implementation(libs.edc.lib.transform) | ||
implementation(libs.edc.dsp.api.configuration) | ||
implementation(libs.edc.api.management.config) | ||
implementation(libs.edc.transaction.spi) | ||
implementation(libs.edc.lib.validator) | ||
implementation(libs.edc.validator.spi) | ||
implementation(libs.swagger.annotations.jakarta) | ||
runtimeOnly(libs.edc.spi.jsonld) | ||
runtimeOnly(libs.edc.json.ld.lib) | ||
} |
120 changes: 120 additions & 0 deletions
120
...ions/vocabulary-api/src/main/java/org/upm/inesdata/vocabulary/VocabularyApiExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package org.upm.inesdata.vocabulary; | ||
|
||
import jakarta.json.Json; | ||
import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration; | ||
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.system.ServiceExtension; | ||
import org.eclipse.edc.spi.system.ServiceExtensionContext; | ||
import org.eclipse.edc.spi.system.health.HealthCheckResult; | ||
import org.eclipse.edc.spi.system.health.HealthCheckService; | ||
import org.eclipse.edc.spi.types.TypeManager; | ||
import org.eclipse.edc.transaction.spi.TransactionContext; | ||
import org.eclipse.edc.transform.spi.TypeTransformerRegistry; | ||
import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry; | ||
import org.eclipse.edc.web.spi.WebService; | ||
import org.upm.inesdata.spi.vocabulary.VocabularyIndex; | ||
import org.upm.inesdata.spi.vocabulary.VocabularyService; | ||
import org.upm.inesdata.vocabulary.controller.VocabularyApiController; | ||
import org.upm.inesdata.vocabulary.service.VocabularyServiceImpl; | ||
import org.upm.inesdata.vocabulary.storage.InMemoryVocabularyIndex; | ||
import org.upm.inesdata.vocabulary.transformer.JsonObjectFromVocabularyTransformer; | ||
import org.upm.inesdata.vocabulary.transformer.JsonObjectToVocabularyTransformer; | ||
import org.upm.inesdata.vocabulary.validator.VocabularyValidator; | ||
|
||
import static org.eclipse.edc.spi.constants.CoreConstants.JSON_LD; | ||
import static org.upm.inesdata.spi.vocabulary.domain.Vocabulary.EDC_VOCABULARY_TYPE; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* Extension that provides an API for managing vocabularies | ||
*/ | ||
@Extension(value = VocabularyApiExtension.NAME) | ||
public class VocabularyApiExtension implements ServiceExtension { | ||
|
||
public static final String NAME = "Vocabulary API Extension"; | ||
private InMemoryVocabularyIndex defaultVocabularyIndex; | ||
|
||
@Inject | ||
private WebService webService; | ||
|
||
@Inject | ||
private VocabularyIndex vocabularyIndex; | ||
|
||
@Inject(required = false) | ||
private HealthCheckService healthCheckService; | ||
|
||
@Inject | ||
private ManagementApiConfiguration config; | ||
|
||
@Inject | ||
private TypeManager typeManager; | ||
|
||
@Inject | ||
private TransactionContext transactionContext; | ||
|
||
@Inject | ||
private TypeTransformerRegistry transformerRegistry; | ||
|
||
@Inject | ||
private JsonObjectValidatorRegistry validator; | ||
|
||
@Override | ||
public String name() { | ||
return NAME; | ||
} | ||
|
||
/** | ||
* Provides a default vocabularyService implementation | ||
*/ | ||
@Provider(isDefault = true) | ||
public VocabularyService vocabularyService() { | ||
return new VocabularyServiceImpl(vocabularyIndex, transactionContext); | ||
} | ||
|
||
/** | ||
* Provides a default in memory vocabularyIndex | ||
*/ | ||
@Provider(isDefault = true) | ||
public VocabularyIndex defaultVocabularyIndex() { | ||
return getVocabularyIndex(); | ||
} | ||
|
||
/** | ||
* Initializes the service | ||
*/ | ||
@Override | ||
public void initialize(ServiceExtensionContext context) { | ||
var monitor = context.getMonitor(); | ||
|
||
var managementApiTransformerRegistry = transformerRegistry.forContext("management-api"); | ||
|
||
var factory = Json.createBuilderFactory(Map.of()); | ||
var jsonLdMapper = typeManager.getMapper(JSON_LD); | ||
managementApiTransformerRegistry.register(new JsonObjectFromVocabularyTransformer(factory, jsonLdMapper)); | ||
managementApiTransformerRegistry.register(new JsonObjectToVocabularyTransformer()); | ||
|
||
validator.register(EDC_VOCABULARY_TYPE, VocabularyValidator.instance()); | ||
var vocabularyApiController = new VocabularyApiController(this.vocabularyService(), managementApiTransformerRegistry, monitor, validator); | ||
webService.registerResource(config.getContextAlias(), vocabularyApiController); | ||
|
||
// contribute to the liveness probe | ||
if (healthCheckService != null) { | ||
var successResult = HealthCheckResult.Builder.newInstance().component("FCC Query API").build(); | ||
healthCheckService.addReadinessProvider(() -> successResult); | ||
healthCheckService.addLivenessProvider(() -> successResult); | ||
} | ||
} | ||
|
||
/** | ||
* Creates a InMemoryVocabularyIndex if not exists | ||
*/ | ||
private InMemoryVocabularyIndex getVocabularyIndex() { | ||
if (defaultVocabularyIndex == null) { | ||
defaultVocabularyIndex = new InMemoryVocabularyIndex(); | ||
} | ||
return defaultVocabularyIndex; | ||
} | ||
} |
133 changes: 133 additions & 0 deletions
133
...ns/vocabulary-api/src/main/java/org/upm/inesdata/vocabulary/controller/VocabularyApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package org.upm.inesdata.vocabulary.controller; | ||
|
||
import io.swagger.v3.oas.annotations.OpenAPIDefinition; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.info.Info; | ||
import io.swagger.v3.oas.annotations.media.ArraySchema; | ||
import io.swagger.v3.oas.annotations.media.Content; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import io.swagger.v3.oas.annotations.parameters.RequestBody; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import jakarta.json.JsonArray; | ||
import jakarta.json.JsonObject; | ||
import org.eclipse.edc.api.model.ApiCoreSchema; | ||
import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractOffer; | ||
|
||
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; | ||
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; | ||
import static org.upm.inesdata.spi.vocabulary.domain.Vocabulary.EDC_VOCABULARY_TYPE; | ||
|
||
/** | ||
* Controller for managing {@link Vocabulary} objects. | ||
*/ | ||
@OpenAPIDefinition( | ||
info = @Info(description = "Manages the connector vocabularies.", | ||
title = "Vocabulary API", version = "1")) | ||
@Tag(name = "Vocabulary") | ||
public interface VocabularyApi { | ||
|
||
/** | ||
* Get all the vocabularies stored in the vocabularies index. No filters are required due | ||
* to the limited number of vocabularies that each data space will manage. | ||
* | ||
* @return list of vocabularies | ||
*/ | ||
@Operation(description = "Obtains all vocabularies", | ||
responses = { | ||
@ApiResponse(responseCode = "200", description = "A list of vocabularies", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ContractOffer.class)))) | ||
} | ||
) | ||
JsonArray getVocabularies(); | ||
|
||
/** | ||
* Retrieves the {@link Vocabulary} with the given ID | ||
* | ||
* @param id id of the vocabulary | ||
* @return JsonObject with the vocabulary information | ||
*/ | ||
@Operation(description = "Gets a vocabulary with the given ID", | ||
responses = { | ||
@ApiResponse(responseCode = "200", description = "The vocabulary", | ||
content = @Content(schema = @Schema(implementation = VocabularyOutputSchema.class))), | ||
@ApiResponse(responseCode = "400", description = "Request was malformed, e.g. id was null", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))), | ||
@ApiResponse(responseCode = "404", description = "A vocabulary with the given ID does not exist", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))) | ||
} | ||
) | ||
JsonObject getVocabulary(String id); | ||
|
||
/** | ||
* Creates a new vocabulary | ||
* | ||
* @param vocabulary the vocabulary | ||
* @return JsonObject with the created vocabulary | ||
*/ | ||
@Operation(description = "Creates a new vocabulary", | ||
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = VocabularyOutputSchema.class))), | ||
responses = { | ||
@ApiResponse(responseCode = "200", description = "Vocabulary was created successfully", | ||
content = @Content(schema = @Schema(implementation = ApiCoreSchema.IdResponseSchema.class))), | ||
@ApiResponse(responseCode = "400", description = "Request body was malformed", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))), | ||
@ApiResponse(responseCode = "409", description = "Could not create vocabulary, because a vocabulary with that ID already exists", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))) } | ||
) | ||
JsonObject createVocabulary(JsonObject vocabylary); | ||
|
||
/** | ||
* Updates a vocabulary | ||
* | ||
* @param vocabulary the vocabulary to be updated | ||
* @return JsonObject with the updated vocabulary | ||
*/ | ||
@Operation(description = "Updates a vocabulary with the given ID if it exists. If the vocabulary is not found, no further action is taken.", | ||
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = VocabularyOutputSchema.class))), | ||
responses = { | ||
@ApiResponse(responseCode = "204", description = "Vocabulary was updated successfully"), | ||
@ApiResponse(responseCode = "404", description = "Vocabulary could not be updated, because it does not exist."), | ||
@ApiResponse(responseCode = "400", description = "Request was malformed, e.g. id was null", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))), | ||
}) | ||
void updateVocabulary(JsonObject vocabulary); | ||
|
||
/** | ||
* Removes the {@link Vocabulary} with the given ID | ||
* | ||
* @param id id of the vocabulary | ||
* @return JsonObject with the updated vocabulary | ||
*/ | ||
@Operation(description = "Removes a vocabulary with the given ID if possible", | ||
responses = { | ||
@ApiResponse(responseCode = "204", description = "Vocabulary was deleted successfully"), | ||
@ApiResponse(responseCode = "400", description = "Request was malformed, e.g. id was null", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))), | ||
@ApiResponse(responseCode = "404", description = "Vocabulary could not be removed, because it does not exist.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))) | ||
}) | ||
void removeVocabulary(String id); | ||
|
||
/** | ||
* Vocabulary output | ||
*/ | ||
@ArraySchema() | ||
@Schema(name = "VocabularyOutput", example = VocabularyOutputSchema.VOCABULARY_OUTPUT_EXAMPLE) | ||
record VocabularyOutputSchema( | ||
@Schema(name = ID) | ||
String id, | ||
@Schema(name = TYPE, example = EDC_VOCABULARY_TYPE) | ||
String name, | ||
String jsonSchema | ||
) { | ||
public static final String VOCABULARY_OUTPUT_EXAMPLE = """ | ||
{ | ||
"@id": "vocabularyId", | ||
"name": "vocabulary name", | ||
"jsonSchema": "{ \\"title\\": \\"vocabulary\\", \\"type\\": \\"object\\", \\"properties\\": { \\"name\\": { \\"type\\": \\"string\\", \\"title\\": \\"Name\\" }, \\"dct:keyword\\": { \\"type\\": \\"array\\", \\"title\\": \\"Keywords\\", \\"items\\": { \\"type\\": \\"string\\" } } }, \\"required\\": [ \\"name\\" ], \\"@context\\": { \\"dct\\": \\"http:\\/\\/purl.org\\/dc\\/terms\\/\" } }" | ||
} | ||
"""; | ||
} | ||
|
||
} |
Oops, something went wrong.