Skip to content

Commit

Permalink
feat: implements credential definition vertical
Browse files Browse the repository at this point in the history
  • Loading branch information
wolf4ood committed Feb 7, 2025
1 parent 02723ff commit 3d216d9
Show file tree
Hide file tree
Showing 41 changed files with 2,229 additions and 4 deletions.
2 changes: 2 additions & 0 deletions core/issuerservice/issuerservice-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ plugins {

dependencies {
api(project(":spi:issuerservice:issuerservice-participant-spi"))
api(project(":spi:issuerservice:issuerservice-credential-definition-spi"))

implementation(project(":core:lib:common-lib"))
implementation(libs.edc.lib.store)
testImplementation(libs.edc.junit)
testImplementation(testFixtures(project(":spi:issuerservice:issuerservice-participant-spi")))
testImplementation(testFixtures(project(":spi:issuerservice:issuerservice-credential-definition-spi")))

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

package org.eclipse.edc.issuerservice.defaults;

import org.eclipse.edc.identityhub.spi.issuance.credentials.attestation.AttestationDefinitionStore;
import org.eclipse.edc.issuerservice.defaults.store.InMemoryAttestationDefinitionStore;
import org.eclipse.edc.issuerservice.defaults.store.InMemoryCredentialDefinitionStore;
import org.eclipse.edc.issuerservice.defaults.store.InMemoryParticipantStore;
import org.eclipse.edc.issuerservice.spi.credentialdefinition.store.CredentialDefinitionStore;
import org.eclipse.edc.issuerservice.spi.participant.store.ParticipantStore;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
Expand All @@ -31,4 +35,14 @@ public ParticipantStore createInMemoryParticipantStore() {
return new InMemoryParticipantStore();
}


@Provider(isDefault = true)
public AttestationDefinitionStore createInMemoryAttestationStore() {
return new InMemoryAttestationDefinitionStore();
}

@Provider(isDefault = true)
public CredentialDefinitionStore createInMemoryCredentialDefinitionStore() {
return new InMemoryCredentialDefinitionStore();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2025 Cofinity-X
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Cofinity-X - initial API and implementation
*
*/

package org.eclipse.edc.issuerservice.defaults.store;

import org.eclipse.edc.identityhub.spi.issuance.credentials.attestation.AttestationDefinitionStore;
import org.eclipse.edc.identityhub.spi.issuance.credentials.model.AttestationDefinition;
import org.eclipse.edc.identityhub.store.InMemoryEntityStore;
import org.eclipse.edc.spi.query.QueryResolver;
import org.eclipse.edc.spi.result.StoreResult;
import org.eclipse.edc.store.ReflectionBasedQueryResolver;
import org.jetbrains.annotations.Nullable;

public class InMemoryAttestationDefinitionStore extends InMemoryEntityStore<AttestationDefinition> implements AttestationDefinitionStore {

@Override
public @Nullable AttestationDefinition resolveDefinition(String id) {
return store.get(id);
}

@Override
public StoreResult<Void> delete(String id) {
return super.deleteById(id);
}

@Override
protected String getId(AttestationDefinition newObject) {
return newObject.id();
}

@Override
protected QueryResolver<AttestationDefinition> createQueryResolver() {
return new ReflectionBasedQueryResolver<>(AttestationDefinition.class, criterionOperatorRegistry);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2025 Cofinity-X
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Cofinity-X - initial API and implementation
*
*/

package org.eclipse.edc.issuerservice.defaults.store;

import org.eclipse.edc.identityhub.spi.issuance.credentials.model.CredentialDefinition;
import org.eclipse.edc.identityhub.store.InMemoryEntityStore;
import org.eclipse.edc.issuerservice.spi.credentialdefinition.store.CredentialDefinitionStore;
import org.eclipse.edc.spi.query.QueryResolver;
import org.eclipse.edc.spi.result.StoreResult;
import org.eclipse.edc.store.ReflectionBasedQueryResolver;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static org.eclipse.edc.spi.result.StoreResult.alreadyExists;
import static org.eclipse.edc.spi.result.StoreResult.notFound;
import static org.eclipse.edc.spi.result.StoreResult.success;

public class InMemoryCredentialDefinitionStore extends InMemoryEntityStore<CredentialDefinition> implements CredentialDefinitionStore {


private final Map<String, String> credentialTypes = new HashMap<>();

@Override
public StoreResult<Void> create(CredentialDefinition credentialDefinition) {
lock.writeLock().lock();
try {
if (credentialTypes.containsKey(credentialDefinition.getCredentialType())) {
return alreadyExists(alreadyExistsForTypeErrorMessage(credentialDefinition.getCredentialType()));
}
if (store.containsKey(credentialDefinition.getId())) {
return alreadyExists(alreadyExistsErrorMessage(credentialDefinition.getId()));
}
store.put(credentialDefinition.getId(), credentialDefinition);
credentialTypes.put(credentialDefinition.getCredentialType(), credentialDefinition.getId());
return success(null);
} finally {
lock.writeLock().unlock();
}
}

@Override
public StoreResult<Void> update(CredentialDefinition credentialDefinition) {
lock.writeLock().lock();
try {
if (!store.containsKey(credentialDefinition.getId())) {
return notFound(notFoundErrorMessage(credentialDefinition.getId()));
}
var credentialId = credentialTypes.get(credentialDefinition.getCredentialType());
if (credentialId != null && !credentialId.equals(credentialDefinition.getId())) {
return alreadyExists(alreadyExistsForTypeErrorMessage(credentialDefinition.getCredentialType()));
}
var oldDefinition = store.put(credentialDefinition.getId(), credentialDefinition);

Optional.ofNullable(oldDefinition)
.map(CredentialDefinition::getCredentialType)
.ifPresent(credentialTypes::remove);

return success();
} finally {

Check notice

Code scanning / CodeQL

Missing Override annotation Note

This method overrides
InMemoryEntityStore.deleteById
; it is advisable to add an Override annotation.
This method overrides
CredentialDefinitionStore.deleteById
; it is advisable to add an Override annotation.
lock.writeLock().unlock();
}
}

public StoreResult<Void> deleteById(String id) {
lock.writeLock().lock();
try {
if (!store.containsKey(id)) {
return notFound(notFoundErrorMessage(id));
}
var credential = store.remove(id);
credentialTypes.remove(credential.getCredentialType());
return success();
} finally {
lock.writeLock().unlock();
}
}

@Override
protected String getId(CredentialDefinition newObject) {
return newObject.getId();
}

@Override
protected QueryResolver<CredentialDefinition> createQueryResolver() {
return new ReflectionBasedQueryResolver<>(CredentialDefinition.class, criterionOperatorRegistry);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package org.eclipse.edc.issuerservice.defaults;

import org.eclipse.edc.issuerservice.defaults.store.InMemoryAttestationDefinitionStore;
import org.eclipse.edc.issuerservice.defaults.store.InMemoryCredentialDefinitionStore;
import org.eclipse.edc.issuerservice.defaults.store.InMemoryParticipantStore;
import org.eclipse.edc.junit.extensions.DependencyInjectionExtension;
import org.junit.jupiter.api.Test;
Expand All @@ -26,6 +28,8 @@ class DefaultServiceExtensionTest {
@Test
void verifyDefaultServices(DefaultServiceExtension extension) {
assertThat(extension.createInMemoryParticipantStore()).isInstanceOf(InMemoryParticipantStore.class);
assertThat(extension.createInMemoryCredentialDefinitionStore()).isInstanceOf(InMemoryCredentialDefinitionStore.class);
assertThat(extension.createInMemoryAttestationStore()).isInstanceOf(InMemoryAttestationDefinitionStore.class);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2025 Cofinity-X
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Cofinity-X - initial API and implementation
*
*/

package org.eclipse.edc.issuerservice.defaults.store;

import org.eclipse.edc.issuerservice.spi.credentialdefinition.store.CredentialDefinitionStore;
import org.eclipse.edc.issuerservice.spi.credentialdefinition.store.CredentialDefinitionStoreTestBase;

public class InMemoryCredentialDefinitionStoreTest extends CredentialDefinitionStoreTestBase {

private final InMemoryCredentialDefinitionStore store = new InMemoryCredentialDefinitionStore();

@Override
protected CredentialDefinitionStore getStore() {
return store;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
plugins {
`java-library`
}

dependencies {
api(project(":spi:issuerservice:issuerservice-credential-definition-spi"))
api(project(":spi:issuance-credentials-spi"))

implementation(libs.edc.spi.transaction)
implementation(libs.edc.lib.store)
testImplementation(libs.edc.junit)
testImplementation(testFixtures(project(":spi:issuerservice:issuerservice-credential-definition-spi")))

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2025 Cofinity-X
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Cofinity-X - initial API and implementation
*
*/

package org.eclipse.edc.issuerservice.credentialdefinition;

import org.eclipse.edc.identityhub.spi.issuance.credentials.attestation.AttestationDefinitionStore;
import org.eclipse.edc.issuerservice.spi.credentialdefinition.CredentialDefinitionService;
import org.eclipse.edc.issuerservice.spi.credentialdefinition.store.CredentialDefinitionStore;
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.transaction.spi.TransactionContext;

import static org.eclipse.edc.issuerservice.credentialdefinition.CredentialDefinitionServiceExtension.NAME;

@Extension(value = NAME)
public class CredentialDefinitionServiceExtension implements ServiceExtension {
public static final String NAME = "IssuerService Credential Definition Service Extension";
@Inject
private TransactionContext transactionContext;
@Inject
private CredentialDefinitionStore store;

@Inject
private AttestationDefinitionStore attestationDefinitionStore;

@Provider
public CredentialDefinitionService getParticipantService() {
return new CredentialDefinitionServiceImpl(transactionContext, store, attestationDefinitionStore);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2025 Cofinity-X
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Cofinity-X - initial API and implementation
*
*/

package org.eclipse.edc.issuerservice.credentialdefinition;

import org.eclipse.edc.identityhub.spi.issuance.credentials.attestation.AttestationDefinitionStore;
import org.eclipse.edc.identityhub.spi.issuance.credentials.model.AttestationDefinition;
import org.eclipse.edc.identityhub.spi.issuance.credentials.model.CredentialDefinition;
import org.eclipse.edc.issuerservice.spi.credentialdefinition.CredentialDefinitionService;
import org.eclipse.edc.issuerservice.spi.credentialdefinition.store.CredentialDefinitionStore;
import org.eclipse.edc.spi.query.Criterion;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.ServiceResult;
import org.eclipse.edc.transaction.spi.TransactionContext;

import java.util.Collection;
import java.util.stream.Collectors;

import static org.eclipse.edc.spi.result.ServiceResult.from;

public class CredentialDefinitionServiceImpl implements CredentialDefinitionService {
private final TransactionContext transactionContext;
private final CredentialDefinitionStore credentialDefinitionStore;
private final AttestationDefinitionStore attestationDefinitionStore;

public CredentialDefinitionServiceImpl(TransactionContext transactionContext, CredentialDefinitionStore credentialDefinitionStore, AttestationDefinitionStore attestationDefinitionStore) {
this.transactionContext = transactionContext;
this.credentialDefinitionStore = credentialDefinitionStore;
this.attestationDefinitionStore = attestationDefinitionStore;
}

@Override
public ServiceResult<Void> createCredentialDefinition(CredentialDefinition credentialDefinition) {
return transactionContext.execute(() -> internalCreate(credentialDefinition));

}

@Override
public ServiceResult<Void> deleteCredentialDefinition(String credentialDefinitionId) {
return transactionContext.execute(() -> from(credentialDefinitionStore.deleteById(credentialDefinitionId)));
}

@Override
public ServiceResult<Void> updateCredentialDefinition(CredentialDefinition credentialDefinition) {
return transactionContext.execute(() -> internalUpdate(credentialDefinition));
}

@Override
public ServiceResult<Collection<CredentialDefinition>> queryCredentialDefinitions(QuerySpec querySpec) {
return transactionContext.execute(() -> from(credentialDefinitionStore.query(querySpec)));

}

@Override
public ServiceResult<CredentialDefinition> findById(String credentialDefinitionId) {
return transactionContext.execute(() -> from(credentialDefinitionStore.findById(credentialDefinitionId)));

}

private ServiceResult<Void> internalCreate(CredentialDefinition credentialDefinition) {
return validateAttestations(credentialDefinition)
.compose(u -> from(credentialDefinitionStore.create(credentialDefinition)));
}

private ServiceResult<Void> internalUpdate(CredentialDefinition credentialDefinition) {
return validateAttestations(credentialDefinition)
.compose(u -> from(credentialDefinitionStore.update(credentialDefinition)));
}

private ServiceResult<Void> validateAttestations(CredentialDefinition credentialDefinition) {
var query = QuerySpec.Builder.newInstance()
.filter(Criterion.criterion("id", "in", credentialDefinition.getAttestations()))
.build();
return from(attestationDefinitionStore.query(query))
.compose(attestationDefinitions -> checkAttestations(credentialDefinition, attestationDefinitions));
}

private ServiceResult<Void> checkAttestations(CredentialDefinition credentialDefinition, Collection<AttestationDefinition> attestationDefinitions) {
if (attestationDefinitions.size() != credentialDefinition.getAttestations().size()) {

var attestationsIds = attestationDefinitions.stream().map(AttestationDefinition::id).collect(Collectors.toSet());

var missingAttestations = credentialDefinition.getAttestations().stream()
.filter(attestationId -> !attestationsIds.contains(attestationId))
.collect(Collectors.toSet());

return ServiceResult.badRequest("Attestation definitions [%s] not found".formatted(String.join(",", missingAttestations)));
}
return ServiceResult.success();
}
}
Loading

0 comments on commit 3d216d9

Please sign in to comment.