deps: Refactor dependencies (#3224)

* remove spring dep
move junit, logging, mockito under dep mgmt

* upgrade anti-corruption-layer deps

* async method invocation

* balking, bloc

* bridge to bytecode

* caching

* callback - cqrs

* component - health check

* hexagonal - metadata mapping

* rest of the patterns

* remove checkstyle, take spotless into use
This commit is contained in:
Ilkka Seppälä
2025-03-29 19:34:27 +02:00
committed by GitHub
parent 371439aeaa
commit 0ca162a55c
1863 changed files with 14403 additions and 17632 deletions
@@ -24,7 +24,6 @@
*/
package com.iluwatar.saga.choreography;
/**
* ChoreographyChapter is an interface representing a contract for an external service. In that
* case, a service needs to make a decision what to do further hence the server needs to get all
@@ -62,6 +61,4 @@ public interface ChoreographyChapter {
* @return result {@link Saga}
*/
Saga rollback(Saga saga);
}
@@ -24,10 +24,7 @@
*/
package com.iluwatar.saga.choreography;
/**
* Class representing a service to book a fly.
*/
/** Class representing a service to book a fly. */
public class FlyBookingService extends Service {
public FlyBookingService(ServiceDiscoveryService service) {
super(service);
@@ -24,10 +24,7 @@
*/
package com.iluwatar.saga.choreography;
/**
* Class representing a service to book a hotel.
*/
/** Class representing a service to book a hotel. */
public class HotelBookingService extends Service {
public HotelBookingService(ServiceDiscoveryService service) {
super(service);
@@ -37,6 +34,4 @@ public class HotelBookingService extends Service {
public String getName() {
return "booking a Hotel";
}
}
@@ -24,10 +24,7 @@
*/
package com.iluwatar.saga.choreography;
/**
* Class representing a service to init a new order.
*/
/** Class representing a service to init a new order. */
public class OrderService extends Service {
public OrderService(ServiceDiscoveryService service) {
@@ -41,7 +41,6 @@ public class Saga {
private boolean forward;
private boolean finished;
public static Saga create() {
return new Saga();
}
@@ -53,9 +52,7 @@ public class Saga {
*/
public SagaResult getResult() {
if (finished) {
return forward
? SagaResult.FINISHED
: SagaResult.ROLLBACKED;
return forward ? SagaResult.FINISHED : SagaResult.ROLLBACKED;
}
return SagaResult.PROGRESS;
@@ -130,7 +127,6 @@ public class Saga {
return --pos;
}
private Saga() {
this.chapters = new ArrayList<>();
this.pos = 0;
@@ -142,7 +138,6 @@ public class Saga {
return chapters.get(pos);
}
boolean isPresent() {
return pos >= 0 && pos < chapters.size();
}
@@ -156,13 +151,9 @@ public class Saga {
* outcoming parameter).
*/
public static class Chapter {
@Getter
private final String name;
@Setter
private ChapterResult result;
@Getter
@Setter
private Object inValue;
@Getter private final String name;
@Setter private ChapterResult result;
@Getter @Setter private Object inValue;
public Chapter(String name) {
this.name = name;
@@ -179,19 +170,18 @@ public class Saga {
}
}
/**
* result for chapter.
*/
/** result for chapter. */
public enum ChapterResult {
INIT, SUCCESS, ROLLBACK
INIT,
SUCCESS,
ROLLBACK
}
/**
* result for saga.
*/
/** result for saga. */
public enum SagaResult {
PROGRESS, FINISHED, ROLLBACKED
PROGRESS,
FINISHED,
ROLLBACKED
}
@Override
@@ -31,12 +31,12 @@ import lombok.extern.slf4j.Slf4j;
* an analog of transaction in a database but in terms of microservices architecture this is
* executed in a distributed environment
*
* <p>A saga is a sequence of local transactions in a certain context.
* If one transaction fails for some reason, the saga executes compensating transactions(rollbacks)
* to undo the impact of the preceding transactions.
* <p>A saga is a sequence of local transactions in a certain context. If one transaction fails for
* some reason, the saga executes compensating transactions(rollbacks) to undo the impact of the
* preceding transactions.
*
* <p>In this approach, there are no mediators or orchestrators services.
* All chapters are handled and moved by services manually.
* <p>In this approach, there are no mediators or orchestrators services. All chapters are handled
* and moved by services manually.
*
* <p>The major difference with choreography saga is an ability to handle crashed services
* (otherwise in choreography services very hard to prevent a saga if one of them has been crashed)
@@ -47,24 +47,22 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SagaApplication {
/**
* main method.
*/
/** main method. */
public static void main(String[] args) {
var sd = serviceDiscovery();
var service = sd.findAny();
var goodOrderSaga = service.execute(newSaga("good_order"));
var badOrderSaga = service.execute(newSaga("bad_order"));
LOGGER.info("orders: goodOrder is {}, badOrder is {}",
goodOrderSaga.getResult(), badOrderSaga.getResult());
LOGGER.info(
"orders: goodOrder is {}, badOrder is {}",
goodOrderSaga.getResult(),
badOrderSaga.getResult());
}
private static Saga newSaga(Object value) {
return Saga
.create()
.chapter("init an order").setInValue(value)
return Saga.create()
.chapter("init an order")
.setInValue(value)
.chapter("booking a Fly")
.chapter("booking a Hotel")
.chapter("withdrawing Money");
@@ -72,8 +70,7 @@ public class SagaApplication {
private static ServiceDiscoveryService serviceDiscovery() {
var sd = new ServiceDiscoveryService();
return sd
.discover(new OrderService(sd))
return sd.discover(new OrderService(sd))
.discover(new FlyBookingService(sd))
.discover(new HotelBookingService(sd))
.discover(new WithdrawMoneyService(sd));
@@ -28,7 +28,6 @@ import java.util.function.Supplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Common abstraction class representing services. implementing a general contract @see {@link
* ChoreographyChapter}
@@ -70,21 +69,24 @@ public abstract class Service implements ChoreographyChapter {
}
var finalNextSaga = nextSaga;
return sd.find(chapterName).map(ch -> ch.execute(finalNextSaga))
return sd.find(chapterName)
.map(ch -> ch.execute(finalNextSaga))
.orElseThrow(serviceNotFoundException(chapterName));
}
private Supplier<RuntimeException> serviceNotFoundException(String chServiceName) {
return () -> new RuntimeException(
String.format("the service %s has not been found", chServiceName));
return () ->
new RuntimeException(String.format("the service %s has not been found", chServiceName));
}
@Override
public Saga process(Saga saga) {
var inValue = saga.getCurrentValue();
LOGGER.info("The chapter '{}' has been started. "
LOGGER.info(
"The chapter '{}' has been started. "
+ "The data {} has been stored or calculated successfully",
getName(), inValue);
getName(),
inValue);
saga.setCurrentStatus(Saga.ChapterResult.SUCCESS);
saga.setCurrentValue(inValue);
return saga;
@@ -93,9 +95,11 @@ public abstract class Service implements ChoreographyChapter {
@Override
public Saga rollback(Saga saga) {
var inValue = saga.getCurrentValue();
LOGGER.info("The Rollback for a chapter '{}' has been started. "
LOGGER.info(
"The Rollback for a chapter '{}' has been started. "
+ "The data {} has been rollbacked successfully",
getName(), inValue);
getName(),
inValue);
saga.setCurrentStatus(Saga.ChapterResult.ROLLBACK);
saga.setCurrentValue(inValue);
@@ -110,5 +114,4 @@ public abstract class Service implements ChoreographyChapter {
}
return false;
}
}
@@ -29,9 +29,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
/**
* The class representing a service discovery pattern.
*/
/** The class representing a service discovery pattern. */
public class ServiceDiscoveryService {
private final Map<String, ChoreographyChapter> services;
@@ -57,6 +55,4 @@ public class ServiceDiscoveryService {
public ServiceDiscoveryService() {
this.services = new HashMap<>();
}
}
@@ -24,9 +24,7 @@
*/
package com.iluwatar.saga.choreography;
/**
* Class representing a service to withdraw a money.
*/
/** Class representing a service to withdraw a money. */
public class WithdrawMoneyService extends Service {
public WithdrawMoneyService(ServiceDiscoveryService service) {
@@ -43,7 +41,8 @@ public class WithdrawMoneyService extends Service {
var inValue = saga.getCurrentValue();
if (inValue.equals("bad_order")) {
LOGGER.info("The chapter '{}' has been started. But the exception has been raised."
LOGGER.info(
"The chapter '{}' has been started. But the exception has been raised."
+ "The rollback is about to start",
getName());
saga.setCurrentStatus(Saga.ChapterResult.ROLLBACK);
@@ -32,8 +32,7 @@ import lombok.Getter;
* @param <K> incoming value
*/
public class ChapterResult<K> {
@Getter
private final K value;
@Getter private final K value;
private final State state;
ChapterResult(K value, State state) {
@@ -53,10 +52,9 @@ public class ChapterResult<K> {
return new ChapterResult<>(val, State.FAILURE);
}
/**
* state for chapter.
*/
/** state for chapter. */
public enum State {
SUCCESS, FAILURE
SUCCESS,
FAILURE
}
}
@@ -24,9 +24,7 @@
*/
package com.iluwatar.saga.orchestration;
/**
* Class representing a service to book a fly.
*/
/** Class representing a service to book a fly. */
public class FlyBookingService extends Service<String> {
@Override
public String getName() {
@@ -24,29 +24,30 @@
*/
package com.iluwatar.saga.orchestration;
/**
* Class representing a service to book a hotel.
*/
/** Class representing a service to book a hotel. */
public class HotelBookingService extends Service<String> {
@Override
public String getName() {
return "booking a Hotel";
}
@Override
public ChapterResult<String> rollback(String value) {
if (value.equals("crashed_order")) {
LOGGER.info("The Rollback for a chapter '{}' has been started. "
LOGGER.info(
"The Rollback for a chapter '{}' has been started. "
+ "The data {} has been failed.The saga has been crashed.",
getName(), value);
getName(),
value);
return ChapterResult.failure(value);
}
LOGGER.info("The Rollback for a chapter '{}' has been started. "
LOGGER.info(
"The Rollback for a chapter '{}' has been started. "
+ "The data {} has been rollbacked successfully",
getName(), value);
getName(),
value);
return super.rollback(value);
}
@@ -53,5 +53,4 @@ public interface OrchestrationChapter<K> {
* @return result {@link ChapterResult}
*/
ChapterResult<K> rollback(K value);
}
@@ -24,9 +24,7 @@
*/
package com.iluwatar.saga.orchestration;
/**
* Class representing a service to init a new order.
*/
/** Class representing a service to init a new order. */
public class OrderService extends Service<String> {
@Override
public String getName() {
@@ -37,18 +37,15 @@ public class Saga {
private final List<Chapter> chapters;
private Saga() {
this.chapters = new ArrayList<>();
}
public Saga chapter(String name) {
this.chapters.add(new Chapter(name));
return this;
}
public Chapter get(int idx) {
return chapters.get(idx);
}
@@ -57,21 +54,18 @@ public class Saga {
return idx >= 0 && idx < chapters.size();
}
public static Saga create() {
return new Saga();
}
/**
* result for saga.
*/
/** result for saga. */
public enum Result {
FINISHED, ROLLBACK, CRASHED
FINISHED,
ROLLBACK,
CRASHED
}
/**
* class represents chapter name.
*/
/** class represents chapter name. */
@AllArgsConstructor
@Getter
public static class Chapter {
@@ -31,15 +31,14 @@ import lombok.extern.slf4j.Slf4j;
* an analog of transaction in a database but in terms of microservices architecture this is
* executed in a distributed environment
*
* <p>A saga is a sequence of local transactions in a certain context.
* If one transaction fails for some reason, the saga executes compensating transactions(rollbacks)
* to undo the impact of the preceding transactions.
* <p>A saga is a sequence of local transactions in a certain context. If one transaction fails for
* some reason, the saga executes compensating transactions(rollbacks) to undo the impact of the
* preceding transactions.
*
* <p>In this approach, there is an orchestrator @see {@link SagaOrchestrator}
* that manages all the transactions and directs the participant services to execute local
* transactions based on events. The major difference with choreography saga is an ability to handle
* crashed services (otherwise in choreography services very hard to prevent a saga if one of them
* has been crashed)
* <p>In this approach, there is an orchestrator @see {@link SagaOrchestrator} that manages all the
* transactions and directs the participant services to execute local transactions based on events.
* The major difference with choreography saga is an ability to handle crashed services (otherwise
* in choreography services very hard to prevent a saga if one of them has been crashed)
*
* @see Saga
* @see SagaOrchestrator
@@ -48,9 +47,7 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SagaApplication {
/**
* method to show common saga logic.
*/
/** method to show common saga logic. */
public static void main(String[] args) {
var sagaOrchestrator = new SagaOrchestrator(newSaga(), serviceDiscovery());
@@ -58,14 +55,15 @@ public class SagaApplication {
Saga.Result badOrder = sagaOrchestrator.execute("bad_order");
Saga.Result crashedOrder = sagaOrchestrator.execute("crashed_order");
LOGGER.info("orders: goodOrder is {}, badOrder is {},crashedOrder is {}",
goodOrder, badOrder, crashedOrder);
LOGGER.info(
"orders: goodOrder is {}, badOrder is {},crashedOrder is {}",
goodOrder,
badOrder,
crashedOrder);
}
private static Saga newSaga() {
return Saga
.create()
return Saga.create()
.chapter("init an order")
.chapter("booking a Fly")
.chapter("booking a Hotel")
@@ -31,7 +31,6 @@ import static com.iluwatar.saga.orchestration.Saga.Result.ROLLBACK;
import lombok.extern.slf4j.Slf4j;
/**
* The orchestrator that manages all the transactions and directs the participant services to
* execute local transactions based on events.
@@ -42,12 +41,11 @@ public class SagaOrchestrator {
private final ServiceDiscoveryService sd;
private final CurrentState state;
/**
* Create a new service to orchetrate sagas.
*
* @param saga saga to process
* @param sd service discovery @see {@link ServiceDiscoveryService}
* @param sd service discovery @see {@link ServiceDiscoveryService}
*/
public SagaOrchestrator(Saga saga, ServiceDiscoveryService sd) {
this.saga = saga;
@@ -59,7 +57,7 @@ public class SagaOrchestrator {
* pipeline to execute saga process/story.
*
* @param value incoming value
* @param <K> type for incoming value
* @param <K> type for incoming value
* @return result @see {@link Result}
*/
@SuppressWarnings("unchecked")
@@ -101,15 +99,12 @@ public class SagaOrchestrator {
}
}
if (!saga.isPresent(next)) {
return state.isForward() ? FINISHED : result == CRASHED ? CRASHED : ROLLBACK;
}
}
}
private static class CurrentState {
int currentNumber;
boolean isForward;
@@ -124,7 +119,6 @@ public class SagaOrchestrator {
this.isForward = true;
}
boolean isForward() {
return isForward;
}
@@ -145,5 +139,4 @@ public class SagaOrchestrator {
return currentNumber;
}
}
}
@@ -39,22 +39,23 @@ public abstract class Service<K> implements OrchestrationChapter<K> {
@Override
public abstract String getName();
@Override
public ChapterResult<K> process(K value) {
LOGGER.info("The chapter '{}' has been started. "
LOGGER.info(
"The chapter '{}' has been started. "
+ "The data {} has been stored or calculated successfully",
getName(), value);
getName(),
value);
return ChapterResult.success(value);
}
@Override
public ChapterResult<K> rollback(K value) {
LOGGER.info("The Rollback for a chapter '{}' has been started. "
LOGGER.info(
"The Rollback for a chapter '{}' has been started. "
+ "The data {} has been rollbacked successfully",
getName(), value);
getName(),
value);
return ChapterResult.success(value);
}
}
@@ -28,9 +28,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* The class representing a service discovery pattern.
*/
/** The class representing a service discovery pattern. */
public class ServiceDiscoveryService {
private final Map<String, OrchestrationChapter<?>> services;
@@ -46,6 +44,4 @@ public class ServiceDiscoveryService {
public ServiceDiscoveryService() {
this.services = new HashMap<>();
}
}
@@ -24,9 +24,7 @@
*/
package com.iluwatar.saga.orchestration;
/**
* Class representing a service to withdraw a money.
*/
/** Class representing a service to withdraw a money. */
public class WithdrawMoneyService extends Service<String> {
@Override
public String getName() {
@@ -36,7 +34,8 @@ public class WithdrawMoneyService extends Service<String> {
@Override
public ChapterResult<String> process(String value) {
if (value.equals("bad_order") || value.equals("crashed_order")) {
LOGGER.info("The chapter '{}' has been started. But the exception has been raised."
LOGGER.info(
"The chapter '{}' has been started. But the exception has been raised."
+ "The rollback is about to start",
getName());
return ChapterResult.failure(value);
@@ -35,6 +35,6 @@ import org.junit.jupiter.api.Test;
class SagaApplicationTest {
@Test
void shouldExecuteWithoutException() {
assertDoesNotThrow(() -> SagaApplication.main(new String[]{}));
assertDoesNotThrow(() -> SagaApplication.main(new String[] {}));
}
}
@@ -24,13 +24,11 @@
*/
package com.iluwatar.saga.choreography;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* test to check choreography saga
*/
import org.junit.jupiter.api.Test;
/** test to check choreography saga */
class SagaChoreographyTest {
@Test
@@ -45,9 +43,9 @@ class SagaChoreographyTest {
}
private static Saga newSaga(Object value) {
return Saga
.create()
.chapter("init an order").setInValue(value)
return Saga.create()
.chapter("init an order")
.setInValue(value)
.chapter("booking a Fly")
.chapter("booking a Hotel")
.chapter("withdrawing Money");
@@ -55,8 +53,7 @@ class SagaChoreographyTest {
private static ServiceDiscoveryService serviceDiscovery() {
var sd = new ServiceDiscoveryService();
return sd
.discover(new OrderService(sd))
return sd.discover(new OrderService(sd))
.discover(new FlyBookingService(sd))
.discover(new HotelBookingService(sd))
.discover(new WithdrawMoneyService(sd));
@@ -28,13 +28,11 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import org.junit.jupiter.api.Test;
/**
* Test if the application starts without throwing an exception.
*/
/** Test if the application starts without throwing an exception. */
class SagaApplicationTest {
@Test
void shouldExecuteApplicationWithoutException() {
assertDoesNotThrow(() -> SagaApplication.main(new String[]{}));
assertDoesNotThrow(() -> SagaApplication.main(new String[] {}));
}
}
@@ -24,18 +24,15 @@
*/
package com.iluwatar.saga.orchestration;
import org.junit.jupiter.api.Test;
import static com.iluwatar.saga.orchestration.Saga.Result;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
/**
* test to test orchestration logic
*/
/** test to test orchestration logic */
class SagaOrchestratorInternallyTest {
private final List<String> records = new ArrayList<>();
@@ -46,16 +43,12 @@ class SagaOrchestratorInternallyTest {
var result = sagaOrchestrator.execute(1);
assertEquals(Result.ROLLBACK, result);
assertArrayEquals(
new String[]{"+1", "+2", "+3", "+4", "-4", "-3", "-2", "-1"},
records.toArray(new String[]{}));
new String[] {"+1", "+2", "+3", "+4", "-4", "-3", "-2", "-1"},
records.toArray(new String[] {}));
}
private static Saga newSaga() {
return Saga.create()
.chapter("1")
.chapter("2")
.chapter("3")
.chapter("4");
return Saga.create().chapter("1").chapter("2").chapter("3").chapter("4");
}
private ServiceDiscoveryService serviceDiscovery() {
@@ -145,4 +138,4 @@ class SagaOrchestratorInternallyTest {
return ChapterResult.success(value);
}
}
}
}
@@ -24,13 +24,11 @@
*/
package com.iluwatar.saga.orchestration;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* test to check general logic
*/
import org.junit.jupiter.api.Test;
/** test to check general logic */
class SagaOrchestratorTest {
@Test
@@ -44,8 +42,7 @@ class SagaOrchestratorTest {
}
private static Saga newSaga() {
return Saga
.create()
return Saga.create()
.chapter("init an order")
.chapter("booking a Fly")
.chapter("booking a Hotel")
@@ -53,11 +50,10 @@ class SagaOrchestratorTest {
}
private static ServiceDiscoveryService serviceDiscovery() {
return
new ServiceDiscoveryService()
.discover(new OrderService())
.discover(new FlyBookingService())
.discover(new HotelBookingService())
.discover(new WithdrawMoneyService());
return new ServiceDiscoveryService()
.discover(new OrderService())
.discover(new FlyBookingService())
.discover(new HotelBookingService())
.discover(new WithdrawMoneyService());
}
}
}