Skip to content

Commit

Permalink
feat: boostrap issuance process state-machine
Browse files Browse the repository at this point in the history
  • Loading branch information
wolf4ood committed Feb 7, 2025
1 parent b0dce22 commit 3ecc3ab
Show file tree
Hide file tree
Showing 29 changed files with 1,691 additions and 64 deletions.
13 changes: 13 additions & 0 deletions core/issuerservice/issuerservice-issuance/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
`java-library`
}

dependencies {
api(project(":spi:issuance-credentials-spi"))
implementation(project(":core:lib:common-lib"))
implementation(libs.edc.lib.store)
implementation(libs.edc.lib.statemachine)
testImplementation(libs.edc.lib.query)
testImplementation(libs.edc.junit)
testImplementation(testFixtures(project(":spi:issuance-credentials-spi")))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* 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.issuance;

import org.eclipse.edc.identityhub.spi.issuance.credentials.process.IssuanceProcessManager;
import org.eclipse.edc.identityhub.spi.issuance.credentials.process.retry.IssuanceProcessRetryStrategy;
import org.eclipse.edc.identityhub.spi.issuance.credentials.process.store.IssuanceProcessStore;
import org.eclipse.edc.issuerservice.issuance.process.IssuanceProcessManagerImpl;
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.runtime.metamodel.annotation.Setting;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.retry.ExponentialWaitStrategy;
import org.eclipse.edc.spi.system.ExecutorInstrumentation;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.telemetry.Telemetry;
import org.eclipse.edc.statemachine.retry.EntityRetryProcessConfiguration;
import org.jetbrains.annotations.NotNull;

import java.time.Clock;

import static org.eclipse.edc.issuerservice.issuance.IssuanceCoreExtension.NAME;
import static org.eclipse.edc.statemachine.AbstractStateEntityManager.DEFAULT_BATCH_SIZE;
import static org.eclipse.edc.statemachine.AbstractStateEntityManager.DEFAULT_ITERATION_WAIT;
import static org.eclipse.edc.statemachine.AbstractStateEntityManager.DEFAULT_SEND_RETRY_BASE_DELAY;
import static org.eclipse.edc.statemachine.AbstractStateEntityManager.DEFAULT_SEND_RETRY_LIMIT;

@Extension(NAME)
public class IssuanceCoreExtension implements ServiceExtension {

public static final String NAME = "Issuance Core Extension";


@Setting(description = "the iteration wait time in milliseconds in the issuance process state machine. Default value " + DEFAULT_ITERATION_WAIT,
key = "edc.issuer.issuance.state-machine.iteration-wait-millis",
defaultValue = DEFAULT_ITERATION_WAIT + "")
private long stateMachineIterationWaitMillis;

@Setting(description = "the batch size in the issuance process state machine. Default value " + DEFAULT_BATCH_SIZE, key = "edc.issuer.issuance.state-machine.batch-size", defaultValue = DEFAULT_BATCH_SIZE + "")
private int stateMachineBatchSize;

@Setting(description = "how many times a specific operation must be tried before terminating the issuance with error", key = "edc.issuer.issuance.send.retry.limit", defaultValue = DEFAULT_SEND_RETRY_LIMIT + "")
private int sendRetryLimit;

@Setting(description = "The base delay for the issuance retry mechanism in millisecond", key = "edc.issuer.issuance.send.retry.base-delay.ms", defaultValue = DEFAULT_SEND_RETRY_BASE_DELAY + "")
private long sendRetryBaseDelay;

private IssuanceProcessManager issuanceProcessManager;

@Inject
private IssuanceProcessStore issuanceProcessStore;

@Inject
private Monitor monitor;

@Inject
private Telemetry telemetry;

@Inject
private ExecutorInstrumentation executorInstrumentation;

@Inject(required = false)
private IssuanceProcessRetryStrategy retryStrategy;

@Inject
private Clock clock;

@Provider
public IssuanceProcessManager createIssuanceProcessManager() {

if (issuanceProcessManager == null) {
var waitStrategy = retryStrategy != null ? retryStrategy : new ExponentialWaitStrategy(stateMachineIterationWaitMillis);
issuanceProcessManager = IssuanceProcessManagerImpl.Builder.newInstance()
.store(issuanceProcessStore)
.monitor(monitor)
.batchSize(stateMachineBatchSize)
.waitStrategy(waitStrategy)
.telemetry(telemetry)
.clock(clock)
.executorInstrumentation(executorInstrumentation)
.entityRetryProcessConfiguration(getEntityRetryProcessConfiguration())
.build();
}
return issuanceProcessManager;
}

@Override
public void start() {
issuanceProcessManager.start();
}

@Override
public void shutdown() {
if (issuanceProcessManager != null) {
issuanceProcessManager.stop();
}
}

@NotNull
private EntityRetryProcessConfiguration getEntityRetryProcessConfiguration() {
return new EntityRetryProcessConfiguration(sendRetryLimit, () -> new ExponentialWaitStrategy(sendRetryBaseDelay));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.issuance.defaults;

import org.eclipse.edc.identityhub.spi.issuance.credentials.process.store.IssuanceProcessStore;
import org.eclipse.edc.issuerservice.issuance.defaults.store.InMemoryIssuanceProcessStore;
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.query.CriterionOperatorRegistry;
import org.eclipse.edc.spi.system.ServiceExtension;

import java.time.Clock;

import static org.eclipse.edc.issuerservice.issuance.defaults.IssuanceDefaultServiceExtension.NAME;

@Extension(NAME)
public class IssuanceDefaultServiceExtension implements ServiceExtension {

public static final String NAME = "Issuance Default Services Extension";

@Inject
private Clock clock;

@Inject
private CriterionOperatorRegistry criterionOperatorRegistry;

@Provider(isDefault = true)
public IssuanceProcessStore createIssuanceProcessStore() {
return new InMemoryIssuanceProcessStore(clock, criterionOperatorRegistry);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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.issuance.defaults.store;

import org.eclipse.edc.identityhub.spi.issuance.credentials.model.IssuanceProcess;
import org.eclipse.edc.identityhub.spi.issuance.credentials.process.store.IssuanceProcessStore;
import org.eclipse.edc.spi.query.CriterionOperatorRegistry;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.store.InMemoryStatefulEntityStore;

import java.time.Clock;
import java.util.UUID;
import java.util.stream.Stream;

public class InMemoryIssuanceProcessStore extends InMemoryStatefulEntityStore<IssuanceProcess> implements IssuanceProcessStore {

public InMemoryIssuanceProcessStore(Clock clock, CriterionOperatorRegistry criterionOperatorRegistry) {
this(UUID.randomUUID().toString(), clock, criterionOperatorRegistry);
}

public InMemoryIssuanceProcessStore(String leaserId, Clock clock, CriterionOperatorRegistry criterionOperatorRegistry) {
super(IssuanceProcess.class, leaserId, clock, criterionOperatorRegistry);
}

@Override
public Stream<IssuanceProcess> query(QuerySpec querySpec) {
return super.findAll(querySpec);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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.issuance.process;

import org.eclipse.edc.identityhub.spi.issuance.credentials.model.IssuanceProcess;
import org.eclipse.edc.identityhub.spi.issuance.credentials.process.IssuanceProcessManager;
import org.eclipse.edc.identityhub.spi.issuance.credentials.process.store.IssuanceProcessStore;
import org.eclipse.edc.statemachine.AbstractStateEntityManager;
import org.eclipse.edc.statemachine.StateMachineManager;

public class IssuanceProcessManagerImpl extends AbstractStateEntityManager<IssuanceProcess, IssuanceProcessStore> implements IssuanceProcessManager {


private IssuanceProcessManagerImpl() {
}

@Override
protected StateMachineManager.Builder configureStateMachineManager(StateMachineManager.Builder builder) {
return builder;
}

public static class Builder
extends AbstractStateEntityManager.Builder<IssuanceProcess, IssuanceProcessStore, IssuanceProcessManagerImpl, Builder> {

private Builder() {
super(new IssuanceProcessManagerImpl());
}

public static Builder newInstance() {
return new Builder();
}

@Override
public Builder self() {
return this;
}


public IssuanceProcessManagerImpl build() {

Check notice

Code scanning / CodeQL

Missing Override annotation Note

This method overrides
Builder<IssuanceProcess,IssuanceProcessStore,IssuanceProcessManagerImpl,Builder>.build
; it is advisable to add an Override annotation.
super.build();

return manager;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#
# 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
#
#

org.eclipse.edc.issuerservice.issuance.defaults.IssuanceDefaultServiceExtension
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.issuance;


import org.eclipse.edc.boot.system.injection.ObjectFactory;
import org.eclipse.edc.issuerservice.issuance.process.IssuanceProcessManagerImpl;
import org.eclipse.edc.junit.extensions.DependencyInjectionExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(DependencyInjectionExtension.class)
public class IssuanceCoreExtensionTest {


@Test
void verifyProviders(ServiceExtensionContext context, ObjectFactory factory) {
var extension = factory.constructInstance(IssuanceCoreExtension.class);
assertThat(extension.createIssuanceProcessManager()).isInstanceOf(IssuanceProcessManagerImpl.class);

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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.issuance.defaults;

import org.eclipse.edc.issuerservice.issuance.defaults.store.InMemoryIssuanceProcessStore;
import org.eclipse.edc.junit.extensions.DependencyInjectionExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(DependencyInjectionExtension.class)
public class IssuanceDefaultServiceExtensionTest {

@Test
void verifyDefaultServices(IssuanceDefaultServiceExtension extension) {
assertThat(extension.createIssuanceProcessStore()).isInstanceOf(InMemoryIssuanceProcessStore.class);
}
}
Loading

0 comments on commit 3ecc3ab

Please sign in to comment.