From e54ec985a00e8dd58760c7b03522967a3197daf7 Mon Sep 17 00:00:00 2001 From: Yang Bo Date: Fri, 2 Mar 2018 01:09:12 +0800 Subject: [PATCH 1/2] SCB-363 Remove legacy code The support for legacy mode will be dropped, remove all the related code from master branch. --- docs/api/api.md | 168 ----- docs/old_saga.md | 53 -- integration-tests/coverage-aggregate/pom.xml | 20 - pom.xml | 50 +- saga-core/pom.xml | 103 --- .../saga/core/BackwardRecovery.java | 49 -- .../servicecomb/saga/core/Compensation.java | 33 - .../saga/core/CompensationTaskConsumer.java | 69 -- .../saga/core/CompositeSagaLog.java | 40 - .../saga/core/CompositeSagaResponse.java | 48 -- .../servicecomb/saga/core/Descriptive.java | 25 - .../servicecomb/saga/core/EventContext.java | 28 - .../servicecomb/saga/core/EventEnvelope.java | 47 -- .../servicecomb/saga/core/EventStore.java | 25 - .../saga/core/FailedSagaResponse.java | 50 -- .../servicecomb/saga/core/Fallback.java | 25 - .../servicecomb/saga/core/FallbackPolicy.java | 62 -- .../saga/core/ForwardRecovery.java | 53 -- .../servicecomb/saga/core/GraphBasedSaga.java | 132 ---- .../servicecomb/saga/core/IdGenerator.java | 25 - .../saga/core/LoggingRecoveryPolicy.java | 46 -- .../saga/core/LongIdGenerator.java | 30 - .../saga/core/NoOpSagaRequest.java | 107 --- .../servicecomb/saga/core/Operation.java | 33 - .../servicecomb/saga/core/PersistentLog.java | 22 - .../saga/core/PersistentStore.java | 26 - .../servicecomb/saga/core/RecoveryPolicy.java | 26 - .../saga/core/RequestProcessTask.java | 67 -- .../servicecomb/saga/core/RestOperation.java | 59 -- .../apache/servicecomb/saga/core/Saga.java | 27 - .../servicecomb/saga/core/SagaContext.java | 36 - .../saga/core/SagaContextImpl.java | 133 ---- .../servicecomb/saga/core/SagaDefinition.java | 25 - .../servicecomb/saga/core/SagaEndTask.java | 48 -- .../servicecomb/saga/core/SagaEndedEvent.java | 38 - .../servicecomb/saga/core/SagaEvent.java | 39 - .../servicecomb/saga/core/SagaException.java | 29 - .../apache/servicecomb/saga/core/SagaLog.java | 22 - .../servicecomb/saga/core/SagaRequest.java | 48 -- .../saga/core/SagaRequestImpl.java | 153 ---- .../servicecomb/saga/core/SagaResponse.java | 61 -- .../saga/core/SagaStartFailedException.java | 25 - .../servicecomb/saga/core/SagaStartTask.java | 56 -- .../saga/core/SagaStartedEvent.java | 46 -- .../servicecomb/saga/core/SagaState.java | 27 - .../servicecomb/saga/core/SagaTask.java | 31 - .../saga/core/SagaTaskFactory.java | 98 --- .../saga/core/SuccessfulSagaResponse.java | 43 -- .../servicecomb/saga/core/TaskConsumer.java | 29 - .../servicecomb/saga/core/TaskRunner.java | 72 -- .../servicecomb/saga/core/ToJsonFormat.java | 26 - .../servicecomb/saga/core/Transaction.java | 27 - .../saga/core/TransactionAbortedEvent.java | 57 -- .../core/TransactionCompensatedEvent.java | 56 -- .../saga/core/TransactionEndedEvent.java | 56 -- .../saga/core/TransactionFailedException.java | 29 - .../saga/core/TransactionStartedEvent.java | 45 -- .../saga/core/TransactionTaskConsumer.java | 123 ---- .../servicecomb/saga/core/Transport.java | 22 - .../saga/core/TransportFailedException.java | 28 - .../saga/core/actors/ActorBasedSaga.java | 65 -- .../core/actors/ActorBasedSagaFactory.java | 83 --- .../core/actors/CompletionCallbackActor.java | 69 -- .../saga/core/actors/EventContextImpl.java | 60 -- .../saga/core/actors/RequestActor.java | 206 ------ .../saga/core/actors/RequestActorBuilder.java | 108 --- .../saga/core/actors/RequestActorContext.java | 82 --- .../core/actors/messages/AbortMessage.java | 37 - .../actors/messages/AbortRecoveryMessage.java | 33 - .../actors/messages/CompensateMessage.java | 32 - .../messages/CompensationRecoveryMessage.java | 22 - .../core/actors/messages/FailMessage.java | 33 - .../saga/core/actors/messages/Message.java | 21 - .../core/actors/messages/TransactMessage.java | 39 - .../messages/TransactionRecoveryMessage.java | 32 - .../application/SagaExecutionComponent.java | 87 --- .../saga/core/application/SagaFactory.java | 30 - .../interpreter/FromJsonFormat.java | 24 - .../interpreter/RestRequestChecker.java | 55 -- .../saga/core/dag/ByLevelTraveller.java | 83 --- .../core/dag/FromLeafTraversalDirection.java | 38 - .../core/dag/FromRootTraversalDirection.java | 38 - .../saga/core/dag/GraphBasedSagaFactory.java | 80 -- .../saga/core/dag/GraphBuilder.java | 109 --- .../saga/core/dag/GraphCycleDetector.java | 25 - .../saga/core/dag/GraphCycleDetectorImpl.java | 70 -- .../servicecomb/saga/core/dag/Node.java | 86 --- .../dag/SingleLeafDirectedAcyclicGraph.java | 38 - .../servicecomb/saga/core/dag/Traveller.java | 29 - .../saga/core/dag/TraversalDirection.java | 29 - .../ContextAwareEventStore.java | 56 -- .../infrastructure/EmbeddedEventStore.java | 58 -- .../saga/transports/RestTransport.java | 27 - .../saga/transports/TransportFactory.java | 23 - .../saga/core/BackwardRecoveryTest.java | 57 -- .../saga/core/CompensationImpl.java | 27 - .../saga/core/CompositeSagaLogTest.java | 49 -- .../saga/core/CompositeSagaResponseTest.java | 73 -- .../servicecomb/saga/core/DummyEvent.java | 31 - .../saga/core/FallbackPolicyTest.java | 91 --- .../saga/core/ForwardRecoveryTest.java | 59 -- .../saga/core/LongIdGeneratorTest.java | 36 - .../saga/core/RestOperationTest.java | 89 --- .../saga/core/RetrySagaLogTest.java | 80 -- .../saga/core/SagaEndTaskTest.java | 47 -- .../saga/core/SagaEventMatcher.java | 68 -- .../core/SagaExecutionComponentTestBase.java | 250 ------- .../saga/core/SagaIntegrationTest.java | 687 ----------------- .../saga/core/SagaStartTaskTest.java | 64 -- .../saga/core/TransactionImpl.java | 27 - .../ActorBasedSagaExecutionComponentTest.java | 31 - .../actors/ActorBasedSagaIntegrationTest.java | 691 ------------------ .../actors/CompletionCallbackActorTest.java | 138 ---- .../core/actors/EventContextImplTest.java | 93 --- .../core/actors/RequestActorBuilderTest.java | 173 ----- .../saga/core/actors/RequestActorTest.java | 399 ---------- .../DirectedAcyclicGraphTraversalTest.java | 102 --- .../GraphBasedSagaExecutionComponentTest.java | 33 - .../saga/core/dag/GraphBuilderTest.java | 148 ---- .../saga/core/dag/GraphCycleDetectorTest.java | 73 -- .../servicecomb/saga/core/dag/NodeTest.java | 80 -- .../ContextAwareEventStoreTest.java | 43 -- saga-core/src/test/resources/application.conf | 21 - saga-core/src/test/resources/log4j2.xml | 30 - .../conditional-transaction-demo/README.md | 174 ----- .../pom.xml | 301 -------- .../demo/tests/ConditionalTransactionIT.java | 155 ---- .../docker-compose.yaml | 75 -- .../inventory/pom.xml | 74 -- .../inventory/InventoryApplication.java | 29 - .../inventory/InventoryController.java | 89 --- .../inventory/InventoryControllerTest.java | 79 -- .../membership/pom.xml | 74 -- .../membership/MembershipApplication.java | 29 - .../membership/MembershipController.java | 62 -- .../payment/pom.xml | 75 -- .../payment/PaymentApplication.java | 29 - .../payment/PaymentController.java | 84 --- .../payment/PaymentControllerTest.java | 61 -- .../conditional-transaction-demo/pom.xml | 40 - .../supplier/pom.xml | 74 -- .../supplier/SupplierApplication.java | 29 - .../supplier/SupplierController.java | 52 -- .../src/main/resources/META-INF/LICENSE.txt | 202 ----- .../src/main/resources/META-INF/NOTICE.txt | 11 - .../README.md | 168 ----- .../car-rental-service/pom.xml | 85 --- .../demo/car/rental/CarRentalApplication.java | 32 - .../demo/car/rental/CarRentalController.java | 100 --- .../src/main/resources/microservice.yaml | 30 - .../demo-tests/pom.xml | 333 --------- .../servicecomb/saga/demo/tests/DemoIT.java | 150 ---- .../docker-compose.yaml | 101 --- .../flight-booking-service/pom.xml | 85 --- .../booking/FlightBookingApplication.java | 32 - .../booking/FlightBookingController.java | 77 -- .../src/main/resources/microservice.yaml | 30 - .../hotel-reservation-service/pom.xml | 85 --- .../HotelReservationApplication.java | 32 - .../HotelReservationController.java | 78 -- .../src/main/resources/microservice.yaml | 30 - .../payment-service/pom.xml | 85 --- .../saga/demo/payment/PaymentApplication.java | 32 - .../saga/demo/payment/PaymentController.java | 81 -- .../src/main/resources/microservice.yaml | 32 - .../dependency-free-transaction-demo/pom.xml | 67 -- saga-demo/pom.xml | 2 - saga-discovery/pom.xml | 37 - .../saga-discovery-servicecenter/pom.xml | 124 ---- .../center/ServiceCenterDiscoveryConfig.java | 43 -- .../main/resources/META-INF/spring.factories | 18 - .../src/main/resources/microservice.yaml | 30 - .../service/center/DummyController.java | 56 -- .../ServiceCenterDiscoveryApplication.java | 32 - ...rviceCenterDiscoveryRestTransportTest.java | 132 ---- .../src/test/resources/log4j2-test.xml | 30 - .../src/test/resources/registry.yaml | 23 - saga-format/pom.xml | 74 -- .../saga/core/FailedSagaRequestContext.java | 40 - .../saga/core/JacksonToJsonFormat.java | 65 -- .../saga/core/SagaRequestContext.java | 37 - .../core/SuccessfulSagaRequestContext.java | 41 -- .../saga/format/ChildrenExtractor.java | 55 -- .../saga/format/JacksonFallback.java | 64 -- .../saga/format/JacksonFromJsonFormat.java | 58 -- .../saga/format/JacksonRestCompensation.java | 52 -- .../saga/format/JacksonRestFallback.java | 43 -- .../saga/format/JacksonRestOperation.java | 62 -- .../saga/format/JacksonRestTransaction.java | 36 - .../saga/format/JacksonSagaEventFormat.java | 114 --- .../saga/format/JsonFailedSagaResponse.java | 29 - .../saga/format/JsonRestSagaRequest.java | 72 -- .../saga/format/JsonSagaDefinition.java | 60 -- .../saga/format/JsonSagaRequest.java | 39 - .../format/JsonSuccessfulSagaResponse.java | 30 - .../saga/format/SagaEventFormat.java | 25 - .../saga/format/TransportAware.java | 26 - .../saga/format/ChildrenExtractorTest.java | 75 -- .../format/JacksonFromJsonFormatTest.java | 261 ------- .../saga/format/JacksonRestOperationTest.java | 69 -- .../saga/format/JsonRestSagaRequestTest.java | 95 --- .../saga/format/JsonSagaDefinitionTest.java | 34 - .../saga/format/SagaEventFormatTest.java | 180 ----- saga-performance/README.md | 47 -- saga-performance/images/grafana.png | Bin 15508 -> 0 bytes saga-performance/scripts/saga.jmx | 289 -------- saga-persistence/pom.xml | 36 - saga-persistence/saga-persistence-jpa/pom.xml | 89 --- .../jpa/EclipseLinkJpaConfiguration.java | 50 -- .../main/resources/META-INF/spring.factories | 18 - saga-spring/pom.xml | 233 ------ .../saga/spring/JpaPersistentStore.java | 69 -- .../saga/spring/SagaController.java | 222 ------ .../saga/spring/SagaEventEntity.java | 85 --- .../saga/spring/SagaEventRepo.java | 44 -- .../spring/SagaExecutionQueryService.java | 160 ---- .../saga/spring/SagaRecoveryListener.java | 37 - .../saga/spring/SagaShutdownListener.java | 42 -- .../saga/spring/SagaSpringApplication.java | 39 - .../saga/spring/SagaSpringConfig.java | 136 ---- .../src/main/resources/META-INF/aop.xml | 25 - .../main/resources/META-INF/spring.factories | 20 - .../src/main/resources/application.conf | 88 --- .../src/main/resources/application.yaml | 30 - saga-spring/src/main/resources/log4j2.xml | 30 - .../src/main/resources/schema-postgresql.sql | 26 - .../ActorBasedSagaSpringApplicationTest.java | 25 - .../GraphBasedSagaSpringApplicationTest.java | 25 - .../saga/spring/GreetingController.java | 42 -- .../saga/spring/SagaRecoveryTest.java | 181 ----- .../saga/spring/SagaServiceDiscoveryTest.java | 113 --- .../spring/SagaSpringApplicationTestBase.java | 390 ---------- saga-spring/src/test/resources/data.sql | 29 - .../src/test/resources/log4j2-test.xml | 30 - saga-spring/src/test/resources/registry.yaml | 23 - saga-web/pom.xml | 130 ---- .../saga/web/SagaWebApplication.java | 34 - saga-web/src/main/resources/application.yaml | 29 - saga-web/src/main/resources/microservice.yaml | 31 - .../src/main/resources/static/css/request.css | 66 -- .../src/main/resources/static/css/style.css | 41 -- .../src/main/resources/static/detail.html | 174 ----- saga-web/src/main/resources/static/index.html | 31 - saga-web/src/main/resources/static/js/date.js | 660 ----------------- .../src/main/resources/static/js/request.js | 294 -------- .../src/main/resources/static/js/table.js | 128 ---- .../src/main/resources/static/request.html | 232 ------ .../src/main/resources/static/result.html | 67 -- transports/pom.xml | 39 - .../transport-httpclient-spring/pom.xml | 80 -- .../transports/HttpClientTransportConfig.java | 40 - .../main/resources/META-INF/spring.factories | 19 - .../saga/transports/RestTransportTest.java | 123 ---- .../src/test/resources/log4j2.xml | 30 - transports/transport-httpclient/pom.xml | 63 -- .../httpclient/HttpClientTransport.java | 121 --- .../httpclient/HttpClientTransportTest.java | 192 ----- .../src/test/resources/log4j2.xml | 30 - transports/transport-resttemplate/pom.xml | 71 -- .../resttemplate/RestTemplateTransport.java | 121 --- 260 files changed, 4 insertions(+), 20094 deletions(-) delete mode 100755 docs/api/api.md delete mode 100755 docs/old_saga.md delete mode 100644 saga-core/pom.xml delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/BackwardRecovery.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/Compensation.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/CompensationTaskConsumer.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/CompositeSagaLog.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/CompositeSagaResponse.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/Descriptive.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/EventContext.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/EventEnvelope.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/EventStore.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/FailedSagaResponse.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/Fallback.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/FallbackPolicy.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/ForwardRecovery.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/GraphBasedSaga.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/IdGenerator.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/LoggingRecoveryPolicy.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/LongIdGenerator.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/NoOpSagaRequest.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/Operation.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/PersistentLog.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/PersistentStore.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/RecoveryPolicy.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/RequestProcessTask.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/RestOperation.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/Saga.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaContext.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaContextImpl.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaDefinition.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEndTask.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEndedEvent.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEvent.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaException.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaLog.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaRequest.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaRequestImpl.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaResponse.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartFailedException.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartTask.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartedEvent.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaState.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaTask.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaTaskFactory.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/SuccessfulSagaResponse.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/TaskConsumer.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/TaskRunner.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/ToJsonFormat.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/Transaction.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionAbortedEvent.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionCompensatedEvent.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionEndedEvent.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionFailedException.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionStartedEvent.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionTaskConsumer.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/Transport.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/TransportFailedException.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/ActorBasedSaga.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaFactory.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/CompletionCallbackActor.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/EventContextImpl.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActor.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActorBuilder.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActorContext.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/AbortMessage.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/AbortRecoveryMessage.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/CompensateMessage.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/CompensationRecoveryMessage.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/FailMessage.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/Message.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/TransactMessage.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/TransactionRecoveryMessage.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/application/SagaExecutionComponent.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/application/SagaFactory.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/application/interpreter/FromJsonFormat.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/application/interpreter/RestRequestChecker.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/ByLevelTraveller.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/FromLeafTraversalDirection.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/FromRootTraversalDirection.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphBasedSagaFactory.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphBuilder.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetector.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetectorImpl.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/Node.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/SingleLeafDirectedAcyclicGraph.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/Traveller.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/TraversalDirection.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/infrastructure/ContextAwareEventStore.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/infrastructure/EmbeddedEventStore.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/transports/RestTransport.java delete mode 100644 saga-core/src/main/java/org/apache/servicecomb/saga/transports/TransportFactory.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/BackwardRecoveryTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/CompensationImpl.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/CompositeSagaLogTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/CompositeSagaResponseTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/DummyEvent.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/FallbackPolicyTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/ForwardRecoveryTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/LongIdGeneratorTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/RestOperationTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/RetrySagaLogTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaEndTaskTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaEventMatcher.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaExecutionComponentTestBase.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaIntegrationTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaStartTaskTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/TransactionImpl.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaExecutionComponentTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaIntegrationTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/CompletionCallbackActorTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/EventContextImplTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/RequestActorBuilderTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/RequestActorTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/DirectedAcyclicGraphTraversalTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphBasedSagaExecutionComponentTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphBuilderTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetectorTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/NodeTest.java delete mode 100644 saga-core/src/test/java/org/apache/servicecomb/saga/infrastructure/ContextAwareEventStoreTest.java delete mode 100644 saga-core/src/test/resources/application.conf delete mode 100644 saga-core/src/test/resources/log4j2.xml delete mode 100755 saga-demo/conditional-transaction-demo/README.md delete mode 100644 saga-demo/conditional-transaction-demo/conditional-transaction-demo-tests/pom.xml delete mode 100644 saga-demo/conditional-transaction-demo/conditional-transaction-demo-tests/src/test/java/org/apache/servicecomb/saga/demo/tests/ConditionalTransactionIT.java delete mode 100755 saga-demo/conditional-transaction-demo/docker-compose.yaml delete mode 100644 saga-demo/conditional-transaction-demo/inventory/pom.xml delete mode 100644 saga-demo/conditional-transaction-demo/inventory/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryApplication.java delete mode 100644 saga-demo/conditional-transaction-demo/inventory/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryController.java delete mode 100644 saga-demo/conditional-transaction-demo/inventory/src/test/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryControllerTest.java delete mode 100644 saga-demo/conditional-transaction-demo/membership/pom.xml delete mode 100644 saga-demo/conditional-transaction-demo/membership/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/membership/MembershipApplication.java delete mode 100644 saga-demo/conditional-transaction-demo/membership/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/membership/MembershipController.java delete mode 100644 saga-demo/conditional-transaction-demo/payment/pom.xml delete mode 100644 saga-demo/conditional-transaction-demo/payment/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentApplication.java delete mode 100644 saga-demo/conditional-transaction-demo/payment/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentController.java delete mode 100644 saga-demo/conditional-transaction-demo/payment/src/test/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentControllerTest.java delete mode 100644 saga-demo/conditional-transaction-demo/pom.xml delete mode 100644 saga-demo/conditional-transaction-demo/supplier/pom.xml delete mode 100644 saga-demo/conditional-transaction-demo/supplier/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/supplier/SupplierApplication.java delete mode 100644 saga-demo/conditional-transaction-demo/supplier/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/supplier/SupplierController.java delete mode 100644 saga-demo/conditional-transaction-demo/supplier/src/main/resources/META-INF/LICENSE.txt delete mode 100644 saga-demo/conditional-transaction-demo/supplier/src/main/resources/META-INF/NOTICE.txt delete mode 100755 saga-demo/dependency-free-transaction-demo/README.md delete mode 100644 saga-demo/dependency-free-transaction-demo/car-rental-service/pom.xml delete mode 100644 saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/java/org/apache/servicecomb/saga/demo/car/rental/CarRentalApplication.java delete mode 100644 saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/java/org/apache/servicecomb/saga/demo/car/rental/CarRentalController.java delete mode 100644 saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/resources/microservice.yaml delete mode 100644 saga-demo/dependency-free-transaction-demo/demo-tests/pom.xml delete mode 100644 saga-demo/dependency-free-transaction-demo/demo-tests/src/test/java/org/apache/servicecomb/saga/demo/tests/DemoIT.java delete mode 100755 saga-demo/dependency-free-transaction-demo/docker-compose.yaml delete mode 100644 saga-demo/dependency-free-transaction-demo/flight-booking-service/pom.xml delete mode 100644 saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/java/org/apache/servicecomb/saga/demo/flight/booking/FlightBookingApplication.java delete mode 100644 saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/java/org/apache/servicecomb/saga/demo/flight/booking/FlightBookingController.java delete mode 100644 saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/resources/microservice.yaml delete mode 100644 saga-demo/dependency-free-transaction-demo/hotel-reservation-service/pom.xml delete mode 100644 saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/java/org/apache/servicecomb/saga/demo/hotel/reservation/HotelReservationApplication.java delete mode 100644 saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/java/org/apache/servicecomb/saga/demo/hotel/reservation/HotelReservationController.java delete mode 100644 saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/resources/microservice.yaml delete mode 100644 saga-demo/dependency-free-transaction-demo/payment-service/pom.xml delete mode 100644 saga-demo/dependency-free-transaction-demo/payment-service/src/main/java/org/apache/servicecomb/saga/demo/payment/PaymentApplication.java delete mode 100644 saga-demo/dependency-free-transaction-demo/payment-service/src/main/java/org/apache/servicecomb/saga/demo/payment/PaymentController.java delete mode 100644 saga-demo/dependency-free-transaction-demo/payment-service/src/main/resources/microservice.yaml delete mode 100644 saga-demo/dependency-free-transaction-demo/pom.xml delete mode 100644 saga-discovery/pom.xml delete mode 100644 saga-discovery/saga-discovery-servicecenter/pom.xml delete mode 100644 saga-discovery/saga-discovery-servicecenter/src/main/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryConfig.java delete mode 100644 saga-discovery/saga-discovery-servicecenter/src/main/resources/META-INF/spring.factories delete mode 100644 saga-discovery/saga-discovery-servicecenter/src/main/resources/microservice.yaml delete mode 100644 saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/DummyController.java delete mode 100644 saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryApplication.java delete mode 100644 saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryRestTransportTest.java delete mode 100644 saga-discovery/saga-discovery-servicecenter/src/test/resources/log4j2-test.xml delete mode 100644 saga-discovery/saga-discovery-servicecenter/src/test/resources/registry.yaml delete mode 100644 saga-format/pom.xml delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/core/FailedSagaRequestContext.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/core/JacksonToJsonFormat.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/core/SagaRequestContext.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/core/SuccessfulSagaRequestContext.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/ChildrenExtractor.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonFallback.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonFromJsonFormat.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestCompensation.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestFallback.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestOperation.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestTransaction.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonSagaEventFormat.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonFailedSagaResponse.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonRestSagaRequest.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSagaDefinition.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSagaRequest.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSuccessfulSagaResponse.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/SagaEventFormat.java delete mode 100644 saga-format/src/main/java/org/apache/servicecomb/saga/format/TransportAware.java delete mode 100644 saga-format/src/test/java/org/apache/servicecomb/saga/format/ChildrenExtractorTest.java delete mode 100644 saga-format/src/test/java/org/apache/servicecomb/saga/format/JacksonFromJsonFormatTest.java delete mode 100644 saga-format/src/test/java/org/apache/servicecomb/saga/format/JacksonRestOperationTest.java delete mode 100644 saga-format/src/test/java/org/apache/servicecomb/saga/format/JsonRestSagaRequestTest.java delete mode 100644 saga-format/src/test/java/org/apache/servicecomb/saga/format/JsonSagaDefinitionTest.java delete mode 100644 saga-format/src/test/java/org/apache/servicecomb/saga/format/SagaEventFormatTest.java delete mode 100644 saga-performance/README.md delete mode 100644 saga-performance/images/grafana.png delete mode 100644 saga-performance/scripts/saga.jmx delete mode 100644 saga-persistence/pom.xml delete mode 100644 saga-persistence/saga-persistence-jpa/pom.xml delete mode 100644 saga-persistence/saga-persistence-jpa/src/main/java/org/apache/servicecomb/saga/persistence/jpa/EclipseLinkJpaConfiguration.java delete mode 100644 saga-persistence/saga-persistence-jpa/src/main/resources/META-INF/spring.factories delete mode 100755 saga-spring/pom.xml delete mode 100644 saga-spring/src/main/java/org/apache/servicecomb/saga/spring/JpaPersistentStore.java delete mode 100644 saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaController.java delete mode 100644 saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaEventEntity.java delete mode 100644 saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaEventRepo.java delete mode 100644 saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaExecutionQueryService.java delete mode 100644 saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaRecoveryListener.java delete mode 100644 saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaShutdownListener.java delete mode 100644 saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaSpringApplication.java delete mode 100644 saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaSpringConfig.java delete mode 100644 saga-spring/src/main/resources/META-INF/aop.xml delete mode 100644 saga-spring/src/main/resources/META-INF/spring.factories delete mode 100644 saga-spring/src/main/resources/application.conf delete mode 100644 saga-spring/src/main/resources/application.yaml delete mode 100644 saga-spring/src/main/resources/log4j2.xml delete mode 100644 saga-spring/src/main/resources/schema-postgresql.sql delete mode 100644 saga-spring/src/test/java/org/apache/servicecomb/saga/spring/ActorBasedSagaSpringApplicationTest.java delete mode 100644 saga-spring/src/test/java/org/apache/servicecomb/saga/spring/GraphBasedSagaSpringApplicationTest.java delete mode 100644 saga-spring/src/test/java/org/apache/servicecomb/saga/spring/GreetingController.java delete mode 100644 saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaRecoveryTest.java delete mode 100644 saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaServiceDiscoveryTest.java delete mode 100644 saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaSpringApplicationTestBase.java delete mode 100644 saga-spring/src/test/resources/data.sql delete mode 100644 saga-spring/src/test/resources/log4j2-test.xml delete mode 100644 saga-spring/src/test/resources/registry.yaml delete mode 100644 saga-web/pom.xml delete mode 100644 saga-web/src/main/java/org/apache/servicecomb/saga/web/SagaWebApplication.java delete mode 100644 saga-web/src/main/resources/application.yaml delete mode 100644 saga-web/src/main/resources/microservice.yaml delete mode 100644 saga-web/src/main/resources/static/css/request.css delete mode 100644 saga-web/src/main/resources/static/css/style.css delete mode 100755 saga-web/src/main/resources/static/detail.html delete mode 100644 saga-web/src/main/resources/static/index.html delete mode 100644 saga-web/src/main/resources/static/js/date.js delete mode 100644 saga-web/src/main/resources/static/js/request.js delete mode 100644 saga-web/src/main/resources/static/js/table.js delete mode 100644 saga-web/src/main/resources/static/request.html delete mode 100644 saga-web/src/main/resources/static/result.html delete mode 100644 transports/pom.xml delete mode 100644 transports/transport-httpclient-spring/pom.xml delete mode 100644 transports/transport-httpclient-spring/src/main/java/org/apache/servicecomb/saga/transports/HttpClientTransportConfig.java delete mode 100644 transports/transport-httpclient-spring/src/main/resources/META-INF/spring.factories delete mode 100644 transports/transport-httpclient-spring/src/test/java/org/apache/servicecomb/saga/transports/RestTransportTest.java delete mode 100644 transports/transport-httpclient-spring/src/test/resources/log4j2.xml delete mode 100644 transports/transport-httpclient/pom.xml delete mode 100644 transports/transport-httpclient/src/main/java/org/apache/servicecomb/saga/transports/httpclient/HttpClientTransport.java delete mode 100644 transports/transport-httpclient/src/test/java/org/apache/servicecomb/saga/transports/httpclient/HttpClientTransportTest.java delete mode 100644 transports/transport-httpclient/src/test/resources/log4j2.xml delete mode 100644 transports/transport-resttemplate/pom.xml delete mode 100644 transports/transport-resttemplate/src/main/java/org/apache/servicecomb/saga/transports/resttemplate/RestTemplateTransport.java diff --git a/docs/api/api.md b/docs/api/api.md deleted file mode 100755 index e0a9e8fce..000000000 --- a/docs/api/api.md +++ /dev/null @@ -1,168 +0,0 @@ -# Saga API -### Post transaction and compensation requests to Saga -``` -POST /requests -``` - -#### Description - -1. Define requests in order and recovery policy by JSON format as below,put them to body. -``` -{ - "policy": "", - "requests": [ - { - "id": "", - "type": "", - "serviceName": "", - "parents": [ - - ], - "transaction": { - "method": "", - "path": "", - "params": { - - } - }, - "compensation": { - "method": "", - "path": "", - "params": { - - } - } - } - ] -} -``` -JSON parameters: -- policy - support `BackwardRecovery` or `ForwardRecovery`. -- requests - transactions array. - - id - request id. It should be unique among this collection of requests. - - type - support `rest` for now. - - serviceName - user-defined service name. - - parents - request ids. It means this request is only executed after all requests in the parents field are completed. - - transaction - user-defined transaction that executed by the Saga. - - method - user-defined, HTTP method. - - path - user-defined, HTTP path. - - params - support `form`,`json`,`body`,`query`. - - compensation - user-defined compensation that executed by the Saga. - - method - user-defined, HTTP method. - - path - user-defined, HTTP path. - - params - support `form`,`json`,`body`,`query`. - -2. Set content type to `text/plain`. - -3. Send them to Saga service. - -#### Example request -``` -curl -XPOST -H "Content-Type: text/plain" -d @./request.json http:///requests -``` - -#### Example response -``` -success -``` - -#### Status codes -- **200** – no error -- **400** – bad parameter -- **500** – server error - - -### Get all the Saga events -``` -GET /events -``` - -#### Description -Get all the Saga events. - -#### Example request -``` -curl -XGET http:///events -``` - -#### Example response -``` -{ - "88658e73-eff5-4d31-887e-019201d6b560": [ - { - "id": 1, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:40Z", - "type": "SagaStartedEvent", - "contentJson": "{\"policy\": \"BackwardRecovery\", \"requests\": [{\"id\": \"request-car\", \"type\": \"rest\", \"serviceName\": \"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-hotel\", \"type\": \"rest\", \"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-flight\", \"type\": \"rest\", \"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-payment\", \"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\", \"request-hotel\"], \"serviceName\": \"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}}]}" - }, - { - "id": 2, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:40Z", - "type": "TransactionStartedEvent", - "contentJson": "{\"id\": \"request-flight\", \"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}" - }, - { - "id": 3, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:40Z", - "type": "TransactionStartedEvent", - "contentJson": "{\"id\": \"request-car\", \"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\": \"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}" - }, - { - "id": 4, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:40Z", - "type": "TransactionStartedEvent", - "contentJson": "{\"id\": \"request-hotel\", \"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}" - }, - { - "id": 5, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:40Z", - "type": "TransactionEndedEvent", - "contentJson": "{\"request\": {\"id\": \"request-flight\", \"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\n \\\"content\\\": \\\"Flight booked with id 5b3c462a-b5d4-45b8-b5e4-8c9aa7d1c069 for customer mike\\\"\\n}\"}}" - }, - { - "id": 6, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:40Z", - "type": "TransactionEndedEvent", - "contentJson": "{\"request\": {\"id\": \"request-hotel\", \"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\n \\\"content\\\": \\\"Hotel reserved with id eb2366e1-411d-4352-84fb-6b5ab446ec81 for customer mike\\\"\\n}\"}}" - }, - { - "id": 7, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:41Z", - "type": "TransactionEndedEvent", - "contentJson": "{\"request\": {\"id\": \"request-car\", \"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\": \"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\n \\\"content\\\": \\\"Car rented with id 3c22da64-d4ac-4870-b9bb-54b603721925 for customer mike\\\"\\n}\"}}" - }, - { - "id": 8, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:41Z", - "type": "TransactionStartedEvent", - "contentJson": "{\"id\": \"request-payment\", \"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\", \"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\": \"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}" - }, - { - "id": 9, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:41Z", - "type": "TransactionEndedEvent", - "contentJson": "{\"request\": {\"id\": \"request-payment\", \"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\", \"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\": \"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\n \\\"content\\\": \\\"Payment made for customer mike and remaining balance is 200\\\"\\n}\"}}" - }, - { - "id": 10, - "sagaId": "88658e73-eff5-4d31-887e-019201d6b560", - "creationTime": "2017-09-15T01:15:41Z", - "type": "SagaEndedEvent", - "contentJson": "{}" - } - ] -} -``` - -#### Status codes -- **200** – no error - diff --git a/docs/old_saga.md b/docs/old_saga.md deleted file mode 100755 index 2b79d2212..000000000 --- a/docs/old_saga.md +++ /dev/null @@ -1,53 +0,0 @@ -# Previous Saga's Documentation -## Major Architecture of Saga -* saga-core(transaction and compensation handling logic) -* saga-format(data serialization and deserialization) -* saga-transports(communication protocol implementation such as rest or rpc in the future) -* saga-discovery(service discovery) -* saga-spring(restful service framework) - -![Saga](static_files/saga.png) - -## Prerequisites -You will need: -1. [Oracle JDK 1.8+][jdk] -2. [Maven 3.x][maven] -3. [Docker][docker] -4. [PostgreSQL][postgres] -5. [Service Center(optional)][service_center] -6. [Docker compose(optional)][docker_compose] -7. [Docker machine(optional)][docker_machine] - -[jdk]: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html -[maven]: https://maven.apache.org/install.html -[docker]: https://www.docker.com/get-docker -[postgres]: https://www.postgresql.org/download/ -[service_center]: https://github.com/apache/incubator-servicecomb-service-center -[docker_compose]: https://docs.docker.com/compose/install/ -[docker_machine]: https://docs.docker.com/machine/install-machine/ - -## Building -Download the source code. -``` -git clone https://github.com/apache/incubator-servicecomb-saga.git -``` - -Enter the Saga root directory,build Saga project by maven command and generate a docker image named saga-spring in local. -``` -mvn package -DskipTests -Pdocker -``` - -## Run Services -A `docker-compose.yaml` file is provided to start Saga services and its dependencies(Service center and Mysql) as docker containers. -User also can configure specified Service center or Mysql in `docker-compose.yaml`. - -Enter the Saga root directory, run all service images using command, -``` -docker-compose up -``` - -## Reference API -See [Saga API](docs/api/api.md) for details. - -## Example -See [Saga demo](https://github.com/apache/incubator-servicecomb-saga/tree/master/saga-demo) for details. diff --git a/integration-tests/coverage-aggregate/pom.xml b/integration-tests/coverage-aggregate/pom.xml index a156600c0..cbb67ad9f 100644 --- a/integration-tests/coverage-aggregate/pom.xml +++ b/integration-tests/coverage-aggregate/pom.xml @@ -29,26 +29,6 @@ - - org.apache.servicecomb.saga - saga-core - - - org.apache.servicecomb.saga - saga-format - - - org.apache.servicecomb.saga - saga-spring - - - org.apache.servicecomb.saga.transports - transport-httpclient - - - org.apache.servicecomb.saga.discovery - saga-discovery-servicecenter - org.apache.servicecomb.saga omega-context diff --git a/pom.xml b/pom.xml index 85e94050a..9207e14e3 100755 --- a/pom.xml +++ b/pom.xml @@ -31,19 +31,12 @@ 0.0.3-SNAPSHOT - saga-core - transports - saga-spring docker-build-config - saga-format - saga-discovery - saga-web omega alpha pack-contracts pack-common integration-tests - saga-persistence @@ -121,41 +114,6 @@ - - org.apache.servicecomb.saga - saga-core - 0.0.3-SNAPSHOT - - - org.apache.servicecomb.saga - saga-format - 0.0.3-SNAPSHOT - - - org.apache.servicecomb.saga - saga-spring - 0.0.3-SNAPSHOT - - - org.apache.servicecomb.saga.transports - transport-httpclient - 0.0.3-SNAPSHOT - - - org.apache.servicecomb.saga.transports - transport-httpclient-spring - 0.0.3-SNAPSHOT - - - org.apache.servicecomb.saga.transports - transport-resttemplate - 0.0.3-SNAPSHOT - - - org.apache.servicecomb.saga.discovery - saga-discovery-servicecenter - 0.0.3-SNAPSHOT - org.apache.servicecomb.saga omega-context @@ -212,10 +170,10 @@ 0.0.3-SNAPSHOT - org.apache.servicecomb.saga - saga-persistence-jpa - 0.0.3-SNAPSHOT - + org.apache.servicecomb.saga + saga-persistence-jpa + 0.0.3-SNAPSHOT + commons-io commons-io diff --git a/saga-core/pom.xml b/saga-core/pom.xml deleted file mode 100644 index f9ba4264d..000000000 --- a/saga-core/pom.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - saga - org.apache.servicecomb.saga - 0.0.3-SNAPSHOT - - 4.0.0 - - saga-core - Saga::Core - - - - com.lmax - disruptor - - - org.slf4j - slf4j-api - - - org.apache.logging.log4j - log4j-slf4j-impl - - - org.apache.logging.log4j - log4j-api - - - org.apache.logging.log4j - log4j-core - - - com.typesafe.akka - akka-actor_2.12 - - - com.typesafe.akka - akka-slf4j_2.12 - - - io.kamon - kamon-core_2.12 - - - io.kamon - kamon-annotation_2.12 - - - - - com.typesafe.akka - akka-testkit_2.12 - - - org.scalatest - scalatest_2.12 - - - junit - junit - - - org.hamcrest - hamcrest-all - - - org.mockito - mockito-core - - - org.apache.commons - commons-lang3 - - - org.awaitility - awaitility - - - com.github.seanyinx - unit-scaffolding - - - - diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/BackwardRecovery.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/BackwardRecovery.java deleted file mode 100644 index e46de2fa0..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/BackwardRecovery.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.lang.invoke.MethodHandles; -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -@EnableKamon -public class BackwardRecovery implements RecoveryPolicy { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - @Segment(name = "backwardPolicy", category = "application", library = "kamon") - @Override - public SagaResponse apply(SagaTask task, SagaRequest request, SagaResponse parentResponse) { - try { - return request.transaction().send(request.serviceName(), parentResponse); - } catch (Exception e) { - log.error("Applying {} policy due to failure in transaction {} of service {}", - description(), - request.transaction(), - request.serviceName(), - e - ); - - task.abort(request, e); - throw e; - } - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Compensation.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/Compensation.java deleted file mode 100644 index f642011a1..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Compensation.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface Compensation extends Operation { - - Compensation SAGA_START_COMPENSATION = new Compensation() { - }; - - Compensation SAGA_END_COMPENSATION = new Compensation() { - }; - - int DEFAULT_RETRIES = 3; - - default int retries() { - return DEFAULT_RETRIES; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/CompensationTaskConsumer.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/CompensationTaskConsumer.java deleted file mode 100644 index 736c34d0b..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/CompensationTaskConsumer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.lang.invoke.MethodHandles; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; - -import org.apache.servicecomb.saga.core.dag.Node; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class CompensationTaskConsumer implements TaskConsumer { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private final Map tasks; - private final SagaContext sagaContext; - - CompensationTaskConsumer(Map tasks, SagaContext sagaContext) { - this.tasks = tasks; - this.sagaContext = sagaContext; - } - - @Override - public void consume(Collection> nodes) { - for (Node node : nodes) { - SagaRequest request = node.value(); - - if (sagaContext.isTransactionCompleted(request)) { - log.info("Starting request {} id={}", request.serviceName(), request.id()); - tasks.get(request.task()).compensate(request); - log.info("Completed request {} id={}", request.serviceName(), request.id()); - } - } - } - - @Override - public boolean replay(Collection> nodes) { - - for (Iterator> iterator = nodes.iterator(); iterator.hasNext(); ) { - SagaRequest request = iterator.next().value(); - if (sagaContext.isCompensationCompleted(request)) { - log.info("Skipped completed compensation id={} operation={} while replay", request.id(), request.transaction()); - iterator.remove(); - } else if (!sagaContext.isTransactionCompleted(request)) { - // this transaction never started - log.info("Skipped pending transaction id={} operation={} while replay", request.id(), request.transaction()); - iterator.remove(); - } - } - return !nodes.isEmpty(); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/CompositeSagaLog.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/CompositeSagaLog.java deleted file mode 100644 index 017129aa2..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/CompositeSagaLog.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -class CompositeSagaLog implements SagaLog { - - private final SagaLog embedded; - private final PersistentLog persistent; - - CompositeSagaLog(SagaLog embedded, PersistentLog persistent) { - this.embedded = embedded; - this.persistent = persistent; - } - - @Segment(name = "compositeSagaLog", category = "application", library = "kamon") - @Override - public void offer(SagaEvent sagaEvent) { - persistent.offer(sagaEvent); - embedded.offer(sagaEvent); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/CompositeSagaResponse.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/CompositeSagaResponse.java deleted file mode 100644 index 02ab48c8c..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/CompositeSagaResponse.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.util.Collection; -import java.util.Optional; - -public class CompositeSagaResponse implements SagaResponse { - private final Collection responses; - - public CompositeSagaResponse(Collection responses) { - this.responses = responses; - } - - @Override - public boolean succeeded() { - return responses.stream().allMatch(SagaResponse::succeeded); - } - - @Override - public String body() { - Optional reduce = responses.stream() - .map(SagaResponse::body) - .reduce((a, b) -> a + ", " + b) - .map(combined -> "[" + combined + "]"); - - return reduce.orElse("{}"); - } - - public Collection responses() { - return responses; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Descriptive.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/Descriptive.java deleted file mode 100644 index bd367af80..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Descriptive.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -interface Descriptive { - - default String description() { - return getClass().getSimpleName(); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/EventContext.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/EventContext.java deleted file mode 100644 index 79b0c3e47..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/EventContext.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface EventContext { - void beginTransaction(SagaRequest request); - - void endTransaction(SagaRequest request, SagaResponse response); - - void abortTransaction(SagaRequest request, SagaResponse response); - - void compensateTransaction(SagaRequest request, SagaResponse response); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/EventEnvelope.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/EventEnvelope.java deleted file mode 100644 index 9283b33e0..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/EventEnvelope.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class EventEnvelope { - - public final long id; - public final long timestamp; - public final SagaEvent event; - - public EventEnvelope(long id, SagaEvent event) { - this.id = id; - this.event = event; - this.timestamp = System.currentTimeMillis(); - } - - // TODO: 8/21/2017 this class seems to be useless to saga - public EventEnvelope(long id, long timestamp, SagaEvent event) { - this.id = id; - this.timestamp = timestamp; - this.event = event; - } - - @Override - public String toString() { - return "EventEnvelope{" + - "id=" + id + - ", timestamp=" + timestamp + - ", event={" + event + - "}}"; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/EventStore.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/EventStore.java deleted file mode 100644 index 7b7e6e24a..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/EventStore.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface EventStore extends SagaLog, Iterable { - - void populate(Iterable events); - - long size(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/FailedSagaResponse.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/FailedSagaResponse.java deleted file mode 100644 index 15d1701d0..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/FailedSagaResponse.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.io.PrintWriter; -import java.io.StringWriter; - -public class FailedSagaResponse implements SagaResponse { - - private final String body; - - public FailedSagaResponse(String body) { - this.body = body; - } - - public FailedSagaResponse(Throwable e) { - this.body = stackTrace(e); - } - - @Override - public boolean succeeded() { - return false; - } - - @Override - public String body() { - return body; - } - - private String stackTrace(Throwable e) { - StringWriter writer = new StringWriter(); - e.printStackTrace(new PrintWriter(writer)); - return writer.toString(); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Fallback.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/Fallback.java deleted file mode 100644 index fca68a03c..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Fallback.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface Fallback extends Operation { - - Fallback NOP_FALLBACK = () -> TYPE_NOP; - - String type(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/FallbackPolicy.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/FallbackPolicy.java deleted file mode 100644 index 48ad67dec..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/FallbackPolicy.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.lang.invoke.MethodHandles; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FallbackPolicy { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private final int retryDelay; - - public FallbackPolicy(int retryDelay) { - this.retryDelay = retryDelay; - } - - public SagaResponse apply(String address, Compensation compensation, Fallback fallback) { - for (int i = 0; isRetryable(i, compensation) && !isInterrupted(); i++) { - try { - return compensation.send(address); - } catch (Exception e) { - log.error("Failed to send compensation to {}", address, e); - sleep(retryDelay); - } - } - - log.warn("Falling back after {} failures sending compensation to {}", compensation.retries(), address); - return fallback.send(address); - } - - private boolean isRetryable(int i, Compensation compensation) { - return compensation.retries() < 0 || i <= compensation.retries(); - } - - private boolean isInterrupted() { - return Thread.currentThread().isInterrupted(); - } - - private void sleep(int delay) { - try { - Thread.sleep(delay); - } catch (InterruptedException ignored) { - Thread.currentThread().interrupt(); - } - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/ForwardRecovery.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/ForwardRecovery.java deleted file mode 100644 index c783990ff..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/ForwardRecovery.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.lang.invoke.MethodHandles; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ForwardRecovery implements RecoveryPolicy { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - @Override - public SagaResponse apply(SagaTask task, SagaRequest request, SagaResponse parentResponse) { - try { - do { - try { - return request.transaction().send(request.serviceName(), parentResponse); - } catch (Exception e) { - log.error("Applying {} policy due to failure in transaction {} of service {}", - description(), - request.transaction(), - request.serviceName(), - e - ); - Thread.sleep(request.failRetryDelayMilliseconds()); - } - } while (true); - } catch (InterruptedException ignored) { - log.warn("Applying {} interrupted in transaction {} of service {}", - description(), - request.transaction(), - request.serviceName(), - ignored); - throw new TransactionFailedException(ignored); - } - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/GraphBasedSaga.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/GraphBasedSaga.java deleted file mode 100644 index f4544e3a5..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/GraphBasedSaga.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.lang.invoke.MethodHandles; -import java.util.Map; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.Executors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.servicecomb.saga.core.dag.ByLevelTraveller; -import org.apache.servicecomb.saga.core.dag.FromLeafTraversalDirection; -import org.apache.servicecomb.saga.core.dag.FromRootTraversalDirection; -import org.apache.servicecomb.saga.core.dag.SingleLeafDirectedAcyclicGraph; -import org.apache.servicecomb.saga.core.dag.TraversalDirection; -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class GraphBasedSaga implements Saga { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private final EventStore eventStore; - private final Map tasks; - - private final TaskRunner transactionTaskRunner; - private final TaskRunner compensationTaskRunner; - private final SagaContext sagaContext; - private volatile SagaState currentTaskRunner; - - GraphBasedSaga(EventStore eventStore, - Map tasks, - SagaContext sagaContext, - SingleLeafDirectedAcyclicGraph sagaTaskGraph) { - - this(eventStore, Executors.newFixedThreadPool(5), tasks, sagaContext, sagaTaskGraph); - } - - public GraphBasedSaga(EventStore eventStore, - Executor executor, - Map tasks, - SagaContext sagaContext, - SingleLeafDirectedAcyclicGraph sagaTaskGraph) { - - this.eventStore = eventStore; - this.tasks = tasks; - - this.transactionTaskRunner = new TaskRunner( - traveller(sagaTaskGraph, new FromRootTraversalDirection<>()), - new TransactionTaskConsumer( - tasks, - sagaContext, - new ExecutorCompletionService<>(executor))); - - this.sagaContext = sagaContext; - this.compensationTaskRunner = new TaskRunner( - traveller(sagaTaskGraph, new FromLeafTraversalDirection<>()), - new CompensationTaskConsumer(tasks, sagaContext)); - - currentTaskRunner = transactionTaskRunner; - } - - @Override - @Segment(name = "runSaga", category = "application", library = "kamon") - public SagaResponse run() { - SagaResponse response = SagaResponse.EMPTY_RESPONSE; - log.info("Starting Saga"); - do { - try { - currentTaskRunner.run(); - } catch (TransactionFailedException e) { - response = new FailedSagaResponse(e); - log.error("Failed to run operation", e); - currentTaskRunner = compensationTaskRunner; - - sagaContext.handleHangingTransactions(request -> { - tasks.get(request.task()).commit(request, sagaContext.responseOf(request.parents())); - tasks.get(request.task()).compensate(request); - }); - } - } while (currentTaskRunner.hasNext()); - log.info("Completed Saga"); - return response; - } - - @Override - public void play() { - log.info("Start playing events"); - gatherEvents(eventStore); - - transactionTaskRunner.replay(); - - if (sagaContext.isCompensationStarted()) { - currentTaskRunner = compensationTaskRunner; - compensationTaskRunner.replay(); - } - - log.info("Completed playing events"); - } - - private void gatherEvents(Iterable events) { - for (SagaEvent event : events) { - event.gatherTo(sagaContext); - } - } - - private ByLevelTraveller traveller( - SingleLeafDirectedAcyclicGraph sagaTaskGraph, - TraversalDirection traversalDirection) { - - return new ByLevelTraveller<>(sagaTaskGraph, traversalDirection); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/IdGenerator.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/IdGenerator.java deleted file mode 100644 index 2add2603d..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/IdGenerator.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.io.Serializable; - -public interface IdGenerator { - - T nextId(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/LoggingRecoveryPolicy.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/LoggingRecoveryPolicy.java deleted file mode 100644 index 9173ecadc..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/LoggingRecoveryPolicy.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.lang.invoke.MethodHandles; -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -@EnableKamon -public class LoggingRecoveryPolicy implements RecoveryPolicy { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private final RecoveryPolicy recoveryPolicy; - - public LoggingRecoveryPolicy(RecoveryPolicy recoveryPolicy) { - this.recoveryPolicy = recoveryPolicy; - } - - @Segment(name = "loggingPolicy", category = "application", library = "kamon") - @Override - public SagaResponse apply(SagaTask task, SagaRequest request, SagaResponse parentResponse) { - log.info("Starting request id={} for service {}", request.id(), request.serviceName()); - SagaResponse response = recoveryPolicy.apply(task, request, parentResponse); - log.info("Completed request id={} for service {}", request.id(), request.serviceName()); - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/LongIdGenerator.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/LongIdGenerator.java deleted file mode 100644 index 6b16075b9..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/LongIdGenerator.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.util.concurrent.atomic.AtomicLong; - -public class LongIdGenerator implements IdGenerator { - - private final AtomicLong atomicLong = new AtomicLong(); - - @Override - public Long nextId() { - return atomicLong.incrementAndGet(); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/NoOpSagaRequest.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/NoOpSagaRequest.java deleted file mode 100644 index 56ad05eee..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/NoOpSagaRequest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static org.apache.servicecomb.saga.core.Compensation.SAGA_END_COMPENSATION; -import static org.apache.servicecomb.saga.core.Compensation.SAGA_START_COMPENSATION; -import static org.apache.servicecomb.saga.core.Operation.TYPE_NOP; -import static org.apache.servicecomb.saga.core.SagaTask.SAGA_END_TASK; -import static org.apache.servicecomb.saga.core.SagaTask.SAGA_START_TASK; -import static org.apache.servicecomb.saga.core.Transaction.SAGA_END_TRANSACTION; -import static org.apache.servicecomb.saga.core.Transaction.SAGA_START_TRANSACTION; - -import java.util.Arrays; - -public class NoOpSagaRequest implements SagaRequest { - - public static final SagaRequest SAGA_START_REQUEST = new NoOpSagaRequest( - "saga-start", - SAGA_START_TRANSACTION, - SAGA_START_COMPENSATION, - SAGA_START_TASK); - - public static final SagaRequest SAGA_END_REQUEST = new NoOpSagaRequest( - "saga-end", - SAGA_END_TRANSACTION, - SAGA_END_COMPENSATION, - SAGA_END_TASK); - - private final String id; - private final Transaction transaction; - private final Compensation compensation; - private final String task; - private final String[] parents = {}; - - private NoOpSagaRequest(String id, Transaction transaction, Compensation compensation, String task) { - this.id = id; - this.transaction = transaction; - this.compensation = compensation; - this.task = task; - } - - @Override - public Transaction transaction() { - return transaction; - } - - @Override - public Compensation compensation() { - return compensation; - } - - @Override - public String serviceName() { - return "Saga"; - } - - @Override - public String id() { - return id; - } - - @Override - public String type() { - return TYPE_NOP; - } - - @Override - public String task() { - return task; - } - - @Override - public String[] parents() { - return parents; - } - - @Override - public int failRetryDelayMilliseconds() { - return 50; - } - - @Override - public String toString() { - return "NoOpSagaRequest{" + - "id='" + id + '\'' + - ", transaction=" + transaction + - ", compensation=" + compensation + - ", task='" + task + '\'' + - ", parents=" + Arrays.toString(parents) + - '}'; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Operation.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/Operation.java deleted file mode 100644 index 13b6f8ab8..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Operation.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface Operation { - - String TYPE_NOP = "NOP"; - String TYPE_REST = "rest"; - SagaResponse SUCCESSFUL_SAGA_RESPONSE = new SuccessfulSagaResponse("success"); - - default SagaResponse send(String address) { - return SUCCESSFUL_SAGA_RESPONSE; - } - - default SagaResponse send(String address, SagaResponse response) { - return send(address); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/PersistentLog.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/PersistentLog.java deleted file mode 100644 index 26ec4bcb8..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/PersistentLog.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface PersistentLog { - void offer(SagaEvent sagaEvent); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/PersistentStore.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/PersistentStore.java deleted file mode 100644 index a7620b3cf..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/PersistentStore.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.util.List; -import java.util.Map; - -public interface PersistentStore extends PersistentLog { - - Map> findPendingSagaEvents(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/RecoveryPolicy.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/RecoveryPolicy.java deleted file mode 100644 index c67d64044..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/RecoveryPolicy.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface RecoveryPolicy extends Descriptive { - - String SAGA_FORWARD_RECOVERY_POLICY = "ForwardRecovery"; - String SAGA_BACKWARD_RECOVERY_POLICY = "BackwardRecovery"; - - SagaResponse apply(SagaTask task, SagaRequest request, SagaResponse parentResponse); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/RequestProcessTask.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/RequestProcessTask.java deleted file mode 100644 index e19c7bf41..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/RequestProcessTask.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class RequestProcessTask implements SagaTask { - - private final String sagaId; - private final SagaLog sagaLog; - private final RecoveryPolicy recoveryPolicy; - private final FallbackPolicy fallbackPolicy; - - public RequestProcessTask( - String sagaId, - SagaLog sagaLog, - RecoveryPolicy recoveryPolicy, - FallbackPolicy fallbackPolicy) { - - this.sagaId = sagaId; - this.sagaLog = sagaLog; - this.recoveryPolicy = recoveryPolicy; - this.fallbackPolicy = fallbackPolicy; - } - - @Segment(name = "commit", category = "application", library = "kamon") - @Override - public SagaResponse commit(SagaRequest request, SagaResponse parentResponse) { - sagaLog.offer(new TransactionStartedEvent(sagaId, request)); - - SagaResponse response = recoveryPolicy.apply(this, request, parentResponse); - - sagaLog.offer(new TransactionEndedEvent(sagaId, request, response)); - return response; - } - - @Segment(name = "compensate", category = "application", library = "kamon") - @Override - public void compensate(SagaRequest request) { - Compensation compensation = request.compensation(); - SagaResponse response = fallbackPolicy.apply(request.serviceName(), compensation, request.fallback()); - - sagaLog.offer(new TransactionCompensatedEvent(sagaId, request, response)); - } - - @Override - public void abort(SagaRequest request, Exception e) { - sagaLog.offer(new TransactionAbortedEvent(sagaId, request, e)); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/RestOperation.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/RestOperation.java deleted file mode 100644 index 5cce22de4..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/RestOperation.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static java.util.Collections.emptyMap; - -import org.apache.servicecomb.saga.core.application.interpreter.RestRequestChecker; -import java.util.Map; - -public class RestOperation implements Operation { - - private final String path; - private final String method; - private final Map> params; - - public RestOperation(String path, String method, Map> params) { - RestRequestChecker.checkParameters(method, params); - - this.path = path; - this.method = method; - this.params = params == null? emptyMap() : params; - } - - public String path() { - return path; - } - - public String method() { - return method; - } - - public Map> params() { - return params; - } - - @Override - public String toString() { - return "Operation{" + - "path='" + path + '\'' + - ", method='" + method + '\'' + - ", params=" + params + - '}'; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Saga.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/Saga.java deleted file mode 100644 index 44f62ea55..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Saga.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import kamon.annotation.Segment; - -public interface Saga { - @Segment(name = "runSaga", category = "application", library = "kamon") - SagaResponse run(); - - void play(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaContext.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaContext.java deleted file mode 100644 index 309be4463..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaContext.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.util.function.Consumer; - -public interface SagaContext extends EventContext { - boolean isCompensationStarted(); - - boolean isTransactionCompleted(SagaRequest request); - - boolean isCompensationCompleted(SagaRequest request); - - void handleHangingTransactions(Consumer consumer); - - SagaResponse responseOf(String requestId); - - boolean isChosenChild(SagaRequest request); - - SagaResponse responseOf(String[] parentRequestIds); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaContextImpl.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaContextImpl.java deleted file mode 100644 index 610ae2740..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaContextImpl.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentSkipListSet; -import java.util.function.Consumer; -import java.util.stream.Collectors; - -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; - -public class SagaContextImpl implements SagaContext { - - private final Map completedTransactions; - private final Map completedCompensations; - private final Set abortedTransactions; - private final Map hangingTransactions; - private final FromJsonFormat> childrenExtractor; - - public SagaContextImpl(FromJsonFormat> childrenExtractor) { - this.childrenExtractor = childrenExtractor; - this.completedTransactions = new ConcurrentHashMap<>(); - this.completedCompensations = new HashMap<>(); - this.abortedTransactions = new ConcurrentSkipListSet<>(); - this.hangingTransactions = new ConcurrentHashMap<>(); - } - - @Override - public boolean isCompensationStarted() { - return !abortedTransactions.isEmpty() || !completedCompensations.isEmpty(); - } - - @Override - public boolean isTransactionCompleted(SagaRequest request) { - return completedTransactions.containsKey(request.id()); - } - - @Override - public boolean isCompensationCompleted(SagaRequest request) { - return completedCompensations.containsKey(request.id()); - } - - @Override - public void beginTransaction(SagaRequest request) { - hangingTransactions.put(request.id(), request); - } - - @Override - public void endTransaction(SagaRequest request, SagaResponse response) { - completedTransactions.put(request.id(), response); - hangingTransactions.remove(request.id()); - } - - @Override - public void abortTransaction(SagaRequest request, SagaResponse response) { - completedTransactions.remove(request.id()); - abortedTransactions.add(request.id()); - hangingTransactions.remove(request.id()); - } - - @Override - public void compensateTransaction(SagaRequest request, SagaResponse response) { - completedCompensations.put(request.id(), response); - completedTransactions.remove(request.id()); - } - - @Override - public void handleHangingTransactions(Consumer consumer) { - for (Iterator iterator = hangingTransactions.values().iterator(); iterator.hasNext(); ) { - consumer.accept(iterator.next()); - } - } - - @Override - public SagaResponse responseOf(String requestId) { - return completedTransactions.getOrDefault(requestId, SagaResponse.NONE_RESPONSE); - } - - private List responsesOf(String[] parentRequestIds) { - return Arrays.stream(parentRequestIds) - .map(this::responseOf) - .collect(Collectors.toList()); - } - - @Override - public SagaResponse responseOf(String[] parentRequestIds) { - List responses = responsesOf(parentRequestIds); - - if (responses.isEmpty()) { - return SagaResponse.EMPTY_RESPONSE; - } - - if (responses.size() == 1) { - return responses.get(0); - } - - return new CompositeSagaResponse(responses); - } - - @Override - public boolean isChosenChild(SagaRequest request) { - Set chosenChildren = chosenChildrenOf(request.parents()); - return chosenChildren.isEmpty() || chosenChildren.contains(request.id()); - } - - private Set chosenChildrenOf(String[] parentRequestIds) { - return Arrays.stream(parentRequestIds) - .map(this::responseOf) - .flatMap(sagaResponse -> childrenExtractor.fromJson(sagaResponse.body()).stream()) - .collect(Collectors.toSet()); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaDefinition.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaDefinition.java deleted file mode 100644 index 406c8df58..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaDefinition.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface SagaDefinition { - - RecoveryPolicy policy(); - - SagaRequest[] requests(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEndTask.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEndTask.java deleted file mode 100644 index 69daba7da..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEndTask.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class SagaEndTask implements SagaTask { - - private final String sagaId; - private final SagaLog sagaLog; - - public SagaEndTask(String sagaId, SagaLog sagaLog) { - this.sagaId = sagaId; - this.sagaLog = sagaLog; - } - - @Segment(name = "endTaskCommit", category = "application", library = "kamon") - @Override - public SagaResponse commit(SagaRequest request, SagaResponse parentResponse) { - sagaLog.offer(new SagaEndedEvent(sagaId, request)); - return SagaResponse.EMPTY_RESPONSE; - } - - @Override - public void compensate(SagaRequest request) { - } - - @Override - public void abort(SagaRequest request, Exception e) { - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEndedEvent.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEndedEvent.java deleted file mode 100644 index c6f4f9f07..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEndedEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class SagaEndedEvent extends SagaEvent { - - public SagaEndedEvent(String sagaId, SagaRequest sagaTask) { - super(sagaId, sagaTask); - } - - @Override - public void gatherTo(EventContext sagaContext) { - sagaContext.endTransaction(payload(), SagaResponse.EMPTY_RESPONSE); - } - - @Override - public String toString() { - return "SagaEndedEvent{id=" - + payload().id() - + ", sagaId=" + sagaId - + "}"; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEvent.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEvent.java deleted file mode 100644 index ceb0ebe71..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public abstract class SagaEvent implements Descriptive { - - public final String sagaId; - private final SagaRequest payload; - - public SagaEvent(String sagaId, SagaRequest payload) { - this.sagaId = sagaId; - this.payload = payload; - } - - public SagaRequest payload() { - return payload; - } - - public abstract void gatherTo(EventContext sagaContext); - - public String json(ToJsonFormat toJsonFormat) { - return "{}"; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaException.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaException.java deleted file mode 100644 index 49ce9890f..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class SagaException extends RuntimeException { - - public SagaException(String cause, Throwable e) { - super(cause, e); - } - - public SagaException(String cause) { - super(cause); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaLog.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaLog.java deleted file mode 100644 index 2e07b9f64..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaLog.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface SagaLog extends PersistentLog { - -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaRequest.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaRequest.java deleted file mode 100644 index 337abdde3..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaRequest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static org.apache.servicecomb.saga.core.Fallback.NOP_FALLBACK; - -public interface SagaRequest { - - String PARAM_FORM = "form"; - String PARAM_JSON = "json"; - String PARAM_JSON_BODY = "body"; - String PARAM_QUERY = "query"; - - Transaction transaction(); - - Compensation compensation(); - - default Fallback fallback() { - return NOP_FALLBACK; - } - - String serviceName(); - - String id(); - - String type(); - - String task(); - - String[] parents(); - - int failRetryDelayMilliseconds(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaRequestImpl.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaRequestImpl.java deleted file mode 100644 index cbb7a230e..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaRequestImpl.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static org.apache.servicecomb.saga.core.Fallback.NOP_FALLBACK; - -import java.util.Arrays; - -public class SagaRequestImpl implements SagaRequest { - - private final String id; - private final String serviceName; - private final String type; - private final Transaction transaction; - private final Compensation compensation; - private final String[] parents; - private final Fallback fallback; - private final int failRetryDelayMilliseconds; - - public SagaRequestImpl( - String id, - String serviceName, - String type, - Transaction transaction, - Compensation compensation, - Fallback fallback, - String[] parents, - int failRetryDelayMilliseconds) { - - this.id = id; - this.serviceName = serviceName; - this.type = type; - this.transaction = transaction; - this.compensation = compensation; - this.fallback = fallback; - this.failRetryDelayMilliseconds = failRetryDelayMilliseconds <= 0 ? 50 : failRetryDelayMilliseconds; - // TODO: 2017/10/21 set parent to root when null - this.parents = parents == null ? new String[0] : parents; - } - - public SagaRequestImpl( - String id, - String serviceName, - String type, - Transaction transaction, - Compensation compensation, - Fallback fallback, - String[] parents) { - this(id, serviceName, type, transaction, compensation, fallback, parents, 0); - } - - public SagaRequestImpl( - String id, - String serviceName, - String type, - Transaction transaction, - Compensation compensation, - Fallback fallback) { - this(id, serviceName, type, transaction, compensation, fallback, new String[0]); - } - - public SagaRequestImpl( - String id, - String serviceName, - String type, - Transaction transaction, - Compensation compensation) { - this(id, serviceName, type, transaction, compensation, NOP_FALLBACK, new String[0]); - } - - public SagaRequestImpl( - String id, - String serviceName, - String type, - Transaction transaction, - Compensation compensation, - String[] parents) { - this(id, serviceName, type, transaction, compensation, NOP_FALLBACK, parents); - } - - @Override - public Transaction transaction() { - return transaction; - } - - @Override - public Compensation compensation() { - return compensation; - } - - @Override - public Fallback fallback() { - return fallback; - } - - @Override - public String serviceName() { - return serviceName; - } - - @Override - public String id() { - return id; - } - - @Override - public String type() { - return type; - } - - @Override - public String task() { - return SagaTask.SAGA_REQUEST_TASK; - } - - @Override - public String[] parents() { - return parents; - } - - @Override - public int failRetryDelayMilliseconds() { - return failRetryDelayMilliseconds; - } - - @Override - public String toString() { - return "SagaRequest{" + - "id='" + id + '\'' + - ", serviceName='" + serviceName + '\'' + - ", type='" + type + '\'' + - ", transaction=" + transaction + - ", compensation=" + compensation + - ", fallback=" + fallback + - ", parents=" + Arrays.toString(parents) + - '}'; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaResponse.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaResponse.java deleted file mode 100644 index ecdfe4a03..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaResponse.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface SagaResponse { - - SagaResponse EMPTY_RESPONSE = new SagaResponse() { - @Override - public boolean succeeded() { - return true; - } - - @Override - public String body() { - return "{}"; - } - - @Override - public String toString() { - return "EMPTY_RESPONSE{body={}}"; - } - }; - - SagaResponse NONE_RESPONSE = new SagaResponse() { - @Override - public boolean succeeded() { - return false; - } - - @Override - public String body() { - return "{\n" - + " \"sagaChildren\": [\"none\"]\n" - + "}"; - } - - @Override - public String toString() { - return "NONE_RESPONSE{body={\"sagaChildren\": [\"none\"]\n}}"; - } - }; - - boolean succeeded(); - - String body(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartFailedException.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartFailedException.java deleted file mode 100644 index 0de35da0e..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartFailedException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class SagaStartFailedException extends RuntimeException { - - public SagaStartFailedException(String cause, Throwable e) { - super(cause, e); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartTask.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartTask.java deleted file mode 100644 index d8a6bd122..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartTask.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class SagaStartTask implements SagaTask { - - private final String sagaId; - private final String requestJson; - private final SagaLog sagaLog; - - public SagaStartTask(String sagaId, String requestJson, SagaLog sagaLog) { - this.sagaId = sagaId; - this.requestJson = requestJson; - this.sagaLog = sagaLog; - } - - @Segment(name = "startTaskCommit", category = "application", library = "kamon") - @Override - public SagaResponse commit(SagaRequest request, SagaResponse parentResponse) { - try { - sagaLog.offer(new SagaStartedEvent(sagaId, requestJson, request)); - } catch (Exception e) { - throw new SagaStartFailedException("Failed to persist SagaStartedEvent for " + requestJson, e); - } - return SagaResponse.EMPTY_RESPONSE; - } - - @Override - public void compensate(SagaRequest request) { - sagaLog.offer(new SagaEndedEvent(sagaId, request)); - } - - @Override - public void abort(SagaRequest request, Exception e) { - - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartedEvent.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartedEvent.java deleted file mode 100644 index 0d82feed7..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaStartedEvent.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class SagaStartedEvent extends SagaEvent { - - private final String requestJson; - - public SagaStartedEvent(String sagaId, String requestJson, SagaRequest request) { - super(sagaId, request); - this.requestJson = requestJson; - } - - @Override - public void gatherTo(EventContext sagaContext) { - sagaContext.endTransaction(payload(), SagaResponse.EMPTY_RESPONSE); - } - - @Override - public String json(ToJsonFormat toJsonFormat) { - return requestJson; - } - - @Override - public String toString() { - return "SagaStartedEvent{id=" - + payload().id() - + ", sagaId=" + sagaId - + "}"; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaState.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaState.java deleted file mode 100644 index eae3678e3..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaState.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -interface SagaState { - - boolean hasNext(); - - void run(); - - void replay(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaTask.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaTask.java deleted file mode 100644 index 73efcc0ce..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaTask.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface SagaTask { - - String SAGA_START_TASK = "SagaStart"; - String SAGA_REQUEST_TASK = "SagaRequest"; - String SAGA_END_TASK = "SagaEnd"; - - SagaResponse commit(SagaRequest request, SagaResponse parentResponse); - - void compensate(SagaRequest request); - - void abort(SagaRequest request, Exception e); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaTaskFactory.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaTaskFactory.java deleted file mode 100644 index 0fd24504f..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SagaTaskFactory.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.lang.invoke.MethodHandles; -import java.util.HashMap; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SagaTaskFactory { - private final FallbackPolicy fallbackPolicy; - private final RetrySagaLog retrySagaLog; - private final PersistentStore persistentStore; - - public SagaTaskFactory(int retryDelay, PersistentStore persistentStore) { - this.persistentStore = persistentStore; - - fallbackPolicy = new FallbackPolicy(retryDelay); - retrySagaLog = new RetrySagaLog(persistentStore, retryDelay); - } - - public Map sagaTasks(String sagaId, - String requestJson, - RecoveryPolicy recoveryPolicy, - EventStore sagaLog) { - - SagaLog compositeSagaLog = compositeSagaLog(sagaLog, persistentStore); - - return new HashMap() {{ - put(SagaTask.SAGA_START_TASK, new SagaStartTask(sagaId, requestJson, compositeSagaLog)); - - SagaLog retrySagaLog = compositeSagaLog(sagaLog, SagaTaskFactory.this.retrySagaLog); - put(SagaTask.SAGA_REQUEST_TASK, - new RequestProcessTask(sagaId, retrySagaLog, new LoggingRecoveryPolicy(recoveryPolicy), fallbackPolicy)); - put(SagaTask.SAGA_END_TASK, new SagaEndTask(sagaId, retrySagaLog)); - }}; - } - - private CompositeSagaLog compositeSagaLog(SagaLog sagaLog, PersistentLog persistentLog) { - return new CompositeSagaLog(sagaLog, persistentLog); - } - - static class RetrySagaLog implements PersistentLog { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private final PersistentStore persistentStore; - private final int retryDelay; - - RetrySagaLog(PersistentStore persistentStore, int retryDelay) { - this.persistentStore = persistentStore; - this.retryDelay = retryDelay; - } - - @Override - public void offer(SagaEvent sagaEvent) { - boolean success = false; - do { - try { - persistentStore.offer(sagaEvent); - success = true; - log.info("Persisted saga event {} successfully", sagaEvent); - } catch (Exception e) { - log.error("Failed to persist saga event {}", sagaEvent, e); - sleep(retryDelay); - } - } while (!success && !isInterrupted()); - } - - private boolean isInterrupted() { - return Thread.currentThread().isInterrupted(); - } - - private void sleep(int delay) { - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SuccessfulSagaResponse.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/SuccessfulSagaResponse.java deleted file mode 100644 index d69bdcd08..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/SuccessfulSagaResponse.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class SuccessfulSagaResponse implements SagaResponse { - private final String body; - - public SuccessfulSagaResponse(String body) { - this.body = body; - } - - @Override - public boolean succeeded() { - return true; - } - - @Override - public String body() { - return body; - } - - @Override - public String toString() { - return "SuccessfulSagaResponse{" + - "body='" + body + '\'' + - '}'; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TaskConsumer.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/TaskConsumer.java deleted file mode 100644 index 5ae749462..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TaskConsumer.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.util.Collection; - -import org.apache.servicecomb.saga.core.dag.Node; - -interface TaskConsumer { - - void consume(Collection> nodes); - - boolean replay(Collection> nodes); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TaskRunner.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/TaskRunner.java deleted file mode 100644 index c07800180..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TaskRunner.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import org.apache.servicecomb.saga.core.dag.Node; -import org.apache.servicecomb.saga.core.dag.Traveller; - -import java.util.Collection; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -class TaskRunner implements SagaState { - - private final Traveller traveller; - private final TaskConsumer taskConsumer; - - TaskRunner(Traveller traveller, TaskConsumer taskConsumer) { - this.traveller = traveller; - this.taskConsumer = taskConsumer; - } - - @Override - public boolean hasNext() { - return traveller.hasNext(); - } - - @Segment(name = "runTask", category = "application", library = "kamon") - @Override - public void run() { - Collection> nodes = traveller.nodes(); - - // finish pending tasks from saga log at startup - if (!nodes.isEmpty()) { - taskConsumer.consume(nodes); - nodes.clear(); - } - - while (traveller.hasNext()) { - traveller.next(); - taskConsumer.consume(nodes); - nodes.clear(); - } - } - - @Override - public void replay() { - boolean played = false; - Collection> nodes = traveller.nodes(); - - while (traveller.hasNext() && !played) { - traveller.next(); - played = taskConsumer.replay(nodes); - } - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/ToJsonFormat.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/ToJsonFormat.java deleted file mode 100644 index cd6c44953..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/ToJsonFormat.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface ToJsonFormat { - - String toJson(SagaRequest request); - - String toJson(SagaRequest request, SagaResponse response); - -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Transaction.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/Transaction.java deleted file mode 100644 index fafb84585..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Transaction.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface Transaction extends Operation { - - Transaction SAGA_START_TRANSACTION = new Transaction() { - }; - - Transaction SAGA_END_TRANSACTION = new Transaction() { - }; -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionAbortedEvent.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionAbortedEvent.java deleted file mode 100644 index b117c94b3..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionAbortedEvent.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class TransactionAbortedEvent extends SagaEvent { - - private final SagaResponse response; - - public TransactionAbortedEvent(String sagaId, SagaRequest payload, Exception exception) { - super(sagaId, payload); - this.response = new FailedSagaResponse(exception); - } - - public TransactionAbortedEvent(String sagaId, SagaRequest payload, SagaResponse response) { - super(sagaId, payload); - this.response = response; - } - - @Override - public void gatherTo(EventContext sagaContext) { - // remove from completed operations in order not to compensate it - sagaContext.abortTransaction(payload(), response); - } - - @Override - public String json(ToJsonFormat toJsonFormat) { - return toJsonFormat.toJson(payload(), response); - } - - @Override - public String toString() { - return "TransactionAbortedEvent{id=" - + payload().id() - + ", operation=" - + payload().compensation() - + "}"; - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionCompensatedEvent.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionCompensatedEvent.java deleted file mode 100644 index d6ab2984a..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionCompensatedEvent.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class TransactionCompensatedEvent extends SagaEvent { - - private final SagaResponse response; - - public TransactionCompensatedEvent(String sagaId, SagaRequest request) { - this(sagaId, request, SagaResponse.EMPTY_RESPONSE); - } - - public TransactionCompensatedEvent(String sagaId, SagaRequest request, SagaResponse response) { - super(sagaId, request); - this.response = response; - } - - @Override - public void gatherTo(EventContext sagaContext) { - sagaContext.compensateTransaction(payload(), response); - } - - @Override - public String json(ToJsonFormat toJsonFormat) { - return toJsonFormat.toJson(payload(), response); - } - - @Override - public String toString() { - return "TransactionCompensatedEvent{id=" - + payload().id() - + ", sagaId=" + sagaId - + ", operation=" - + payload().compensation() - + "}"; - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionEndedEvent.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionEndedEvent.java deleted file mode 100644 index 603c542ab..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionEndedEvent.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class TransactionEndedEvent extends SagaEvent { - - private final SagaResponse response; - - public TransactionEndedEvent(String sagaId, SagaRequest request) { - this(sagaId, request, SagaResponse.EMPTY_RESPONSE); - } - - public TransactionEndedEvent(String sagaId, SagaRequest request, SagaResponse response) { - super(sagaId, request); - this.response = response; - } - - @Override - public void gatherTo(EventContext sagaContext) { - sagaContext.endTransaction(payload(), response); - } - - @Override - public String toString() { - return "TransactionEndedEvent{id=" - + payload().id() - + ", sagaId=" + sagaId - + ", operation=" - + payload().transaction() - + "}"; - } - - @Override - public String json(ToJsonFormat toJsonFormat) { - return toJsonFormat.toJson(payload(), response); - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionFailedException.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionFailedException.java deleted file mode 100644 index b55e01a3d..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionFailedException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class TransactionFailedException extends RuntimeException { - - public TransactionFailedException(Throwable throwable) { - super(throwable); - } - - public TransactionFailedException(String cause) { - super(cause); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionStartedEvent.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionStartedEvent.java deleted file mode 100644 index cc3558938..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionStartedEvent.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class TransactionStartedEvent extends SagaEvent { - - public TransactionStartedEvent(String sagaId, SagaRequest transaction) { - super(sagaId, transaction); - } - - @Override - public void gatherTo(EventContext sagaContext) { - sagaContext.beginTransaction(payload()); - } - - @Override - public String toString() { - return "TransactionStartedEvent{id=" - + payload().id() - + ", sagaId=" + sagaId - + ", operation=" - + payload().transaction() - + "}"; - } - - @Override - public String json(ToJsonFormat toJsonFormat) { - return toJsonFormat.toJson(payload()); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionTaskConsumer.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionTaskConsumer.java deleted file mode 100644 index af2dc7429..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransactionTaskConsumer.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import org.apache.servicecomb.saga.core.dag.Node; -import java.lang.invoke.MethodHandles; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.CompletionService; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; -import kamon.annotation.Trace; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@EnableKamon -class TransactionTaskConsumer implements TaskConsumer { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private final Map tasks; - private final SagaContext sagaContext; - private final CompletionService executorService; - - TransactionTaskConsumer( - Map tasks, - SagaContext sagaContext, - CompletionService executorService) { - - this.tasks = tasks; - this.sagaContext = sagaContext; - this.executorService = executorService; - } - - @Segment(name = "consumeTask", category = "application", library = "kamon") - @Override - public void consume(Collection> nodes) { - List> futures = new ArrayList<>(nodes.size()); - for (Node node : nodes) { - SagaRequest request = node.value(); - if (sagaContext.isChosenChild(request)) { - futures.add(futureOf(request)); - } - } - - for (int i = 0; i < futures.size(); i++) { - try { - executorService.take().get(); - } catch (ExecutionException e) { - if (e.getCause() instanceof SagaStartFailedException) { - throw ((SagaStartFailedException) e.getCause()); - } - throw new TransactionFailedException(e.getCause()); - } catch (InterruptedException e) { - // TODO: 7/29/2017 what shall we do when system is shutting down? - throw new TransactionFailedException(e); - } - } - } - - @Override - public boolean replay(Collection> nodes) { - for (Iterator> iterator = nodes.iterator(); iterator.hasNext(); ) { - SagaRequest request = iterator.next().value(); - if (sagaContext.isTransactionCompleted(request)) { - log.info("Skipped completed transaction id={} operation={} while replay", request.id(), request.transaction()); - iterator.remove(); - } - } - return !nodes.isEmpty(); - } - - @Segment(name = "submitCallable", category = "application", library = "kamon") - private Future futureOf(SagaRequest request) { - return executorService.submit(new OperationCallable(tasks, request, sagaContext.responseOf(request.parents()))); - } - - @EnableKamon - private static class OperationCallable implements Callable { - - private final SagaRequest request; - private final Map tasks; - private final SagaResponse parentResponse; - - private OperationCallable( - Map tasks, - SagaRequest request, - SagaResponse parentResponse) { - this.request = request; - this.tasks = tasks; - this.parentResponse = parentResponse; - } - - @Trace("runTransactionCallable") - @Override - public Operation call() throws Exception { - tasks.get(request.task()).commit(request, parentResponse); - return request.transaction(); - } - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Transport.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/Transport.java deleted file mode 100644 index 5679e0a4c..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/Transport.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public interface Transport { - -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransportFailedException.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransportFailedException.java deleted file mode 100644 index e01a9d580..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/TransportFailedException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class TransportFailedException extends RuntimeException { - public TransportFailedException(String cause) { - super(cause); - } - - public TransportFailedException(String cause, Throwable e) { - super(cause, e); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/ActorBasedSaga.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/ActorBasedSaga.java deleted file mode 100644 index bf60f988d..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/ActorBasedSaga.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.saga.core.EventContext; -import org.apache.servicecomb.saga.core.EventStore; -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.Saga; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.actors.messages.TransactMessage; -import org.apache.servicecomb.saga.core.SagaEvent; - -import akka.actor.ActorRef; - -public class ActorBasedSaga implements Saga { - private final ActorRef root; - private final ActorRef completionCallback; - private final CompletableFuture future; - private final EventStore sagaLog; - private final EventContext sagaContext; - - ActorBasedSaga(ActorRef root, ActorRef completionCallback, CompletableFuture future, EventStore sagaLog, - EventContext sagaContext) { - this.root = root; - this.completionCallback = completionCallback; - this.future = future; - this.sagaLog = sagaLog; - this.sagaContext = sagaContext; - } - - @Override - public SagaResponse run() { - root.tell(new TransactMessage(NoOpSagaRequest.SAGA_START_REQUEST, SagaResponse.EMPTY_RESPONSE), completionCallback); - - return future.join(); - } - - @Override - public void play() { - gatherEvents(sagaLog); - } - - private void gatherEvents(Iterable events) { - for (SagaEvent event : events) { - event.gatherTo(sagaContext); - } - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaFactory.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaFactory.java deleted file mode 100644 index 8ce22fa6d..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaFactory.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import static akka.actor.ActorRef.noSender; - -import java.util.Set; -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.saga.core.EventStore; -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.application.SagaFactory; -import org.apache.servicecomb.saga.core.PersistentStore; -import org.apache.servicecomb.saga.core.SagaDefinition; -import org.apache.servicecomb.saga.core.SagaTaskFactory; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import scala.concurrent.Await; -import scala.concurrent.duration.Duration; - -public class ActorBasedSagaFactory implements SagaFactory { - private final ActorSystem actorSystem = ActorSystem.create("saga"); - private final RequestActorBuilder actorBuilder; - private final SagaTaskFactory sagaTaskFactory; - - public ActorBasedSagaFactory(int retryDelay, - PersistentStore persistentStore, - FromJsonFormat> childrenExtractor) { - - this.sagaTaskFactory = new SagaTaskFactory(retryDelay, persistentStore); - this.actorBuilder = new RequestActorBuilder(actorSystem, childrenExtractor); - } - - @Override - public ActorBasedSaga createSaga(String requestJson, String sagaId, EventStore sagaLog, SagaDefinition definition) { - - CompletableFuture future = new CompletableFuture<>(); - ActorRef completionCallback = actorSystem.actorOf(CompletionCallbackActor.props(future)); - RequestActorContext context = actorBuilder.build( - definition.requests(), - sagaTaskFactory.sagaTasks(sagaId, - requestJson, - definition.policy(), - sagaLog - ), - completionCallback); - - completionCallback.tell(context, noSender()); - return new ActorBasedSaga( - context.actorOf(NoOpSagaRequest.SAGA_START_REQUEST.id()), - completionCallback, - future, - sagaLog, - new EventContextImpl(context)); - } - - @Override - public boolean isTerminated() { - return actorSystem.whenTerminated().isCompleted(); - } - - @Override - public void terminate() throws Exception { - Await.result(actorSystem.terminate(), Duration.Inf()); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/CompletionCallbackActor.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/CompletionCallbackActor.java deleted file mode 100644 index 7cee4d301..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/CompletionCallbackActor.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.actors.messages.AbortMessage; -import org.apache.servicecomb.saga.core.actors.messages.CompensateMessage; -import org.apache.servicecomb.saga.core.actors.messages.FailMessage; -import org.apache.servicecomb.saga.core.actors.messages.TransactMessage; -import akka.actor.AbstractLoggingActor; -import akka.actor.Props; - -class CompletionCallbackActor extends AbstractLoggingActor { - private final CompletableFuture future; - - private CompletionCallbackActor(CompletableFuture future) { - this.future = future; - } - - static Props props(CompletableFuture future) { - return Props.create(CompletionCallbackActor.class, () -> new CompletionCallbackActor(future)); - } - - @Override - public Receive createReceive() { - return receiveBuilder() - .match(RequestActorContext.class, this::ready) - .build(); - } - - private void ready(RequestActorContext context) { - getContext().become(receiveBuilder() - .match(CompensateMessage.class, message -> end(context, message.response())) - .match(TransactMessage.class, message -> end(context, message.response())) - .match(AbortMessage.class, message -> onAbort(context, message)) - .match(FailMessage.class, message -> end(context, message.response())) - .build()); - } - - private void onAbort(RequestActorContext context, AbortMessage message) { - log().info("saga actor: received abort message of {}", message.response()); - context.actorOf(NoOpSagaRequest.SAGA_END_REQUEST.id()).tell(new CompensateMessage(message.response()), self()); - } - - private void end(RequestActorContext context, SagaResponse response) { - log().info("saga actor: received response {}", response); - future.complete(response); - context.forAll(actor -> getContext().stop(actor)); - getContext().stop(self()); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/EventContextImpl.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/EventContextImpl.java deleted file mode 100644 index 21a2928a7..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/EventContextImpl.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import static akka.actor.ActorRef.noSender; - -import org.apache.servicecomb.saga.core.EventContext; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.actors.messages.AbortRecoveryMessage; -import org.apache.servicecomb.saga.core.actors.messages.CompensationRecoveryMessage; -import org.apache.servicecomb.saga.core.actors.messages.TransactionRecoveryMessage; -import org.apache.servicecomb.saga.core.actors.messages.Message; - -public class EventContextImpl implements EventContext { - private final RequestActorContext context; - - EventContextImpl(RequestActorContext context) { - this.context = context; - } - - @Override - public void beginTransaction(SagaRequest request) { - - } - - @Override - public void endTransaction(SagaRequest request, SagaResponse response) { - sendMessage(request, new TransactionRecoveryMessage(response)); - } - - @Override - public void abortTransaction(SagaRequest request, SagaResponse response) { - sendMessage(request, new AbortRecoveryMessage(response)); - } - - @Override - public void compensateTransaction(SagaRequest request, SagaResponse response) { - sendMessage(request, new CompensationRecoveryMessage()); - } - - private void sendMessage(SagaRequest request, Message message) { - context.actorOf(request.id()).tell(message, noSender()); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActor.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActor.java deleted file mode 100644 index 055174e23..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActor.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import org.apache.servicecomb.saga.core.CompositeSagaResponse; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.SagaStartFailedException; -import org.apache.servicecomb.saga.core.SagaTask; -import org.apache.servicecomb.saga.core.TransactionFailedException; -import org.apache.servicecomb.saga.core.actors.messages.AbortMessage; -import org.apache.servicecomb.saga.core.actors.messages.AbortRecoveryMessage; -import org.apache.servicecomb.saga.core.actors.messages.CompensationRecoveryMessage; -import org.apache.servicecomb.saga.core.actors.messages.FailMessage; -import org.apache.servicecomb.saga.core.actors.messages.Message; -import org.apache.servicecomb.saga.core.actors.messages.TransactMessage; -import org.apache.servicecomb.saga.core.actors.messages.TransactionRecoveryMessage; -import org.apache.servicecomb.saga.core.actors.messages.CompensateMessage; - -import akka.actor.AbstractLoggingActor; -import akka.actor.ActorRef; -import akka.actor.Props; -import akka.japi.pf.ReceiveBuilder; - -public class RequestActor extends AbstractLoggingActor { - private final RequestActorContext context; - private final SagaTask task; - private final SagaRequest request; - - private final List parentResponses; - private final List compensatedChildren; - - private final Receive transacted; - private final Receive aborted; - - static Props props( - RequestActorContext context, - SagaTask task, - SagaRequest request) { - return Props.create(RequestActor.class, () -> new RequestActor(context, task, request)); - } - - private RequestActor( - RequestActorContext context, - SagaTask task, - SagaRequest request) { - this.context = context; - this.task = task; - this.request = request; - this.parentResponses = new ArrayList<>(request.parents().length); - this.compensatedChildren = new LinkedList<>(); - - this.aborted = onReceive(ignored -> { - }).build(); - - this.transacted = onReceive(task::compensate) - .match(CompensationRecoveryMessage.class, message -> getContext().become(aborted)) - .build(); - } - - @Override - public Receive createReceive() { - return receiveBuilder() - .match(TransactMessage.class, - message -> onTransaction(message, () -> task.commit(request, responseOf(parentResponses)))) - .match(TransactionRecoveryMessage.class, this::onTransactRecovery) - .match(AbortRecoveryMessage.class, this::onAbortRecovery) - .match(AbortMessage.class, this::onAbort) - .build(); - } - - private void onAbort(AbortMessage message) { - log().debug("{}: received abort message of {}", request.id(), message.response()); - sendToChildrenButSender(message); - sendToParentsButSender(message); - - getContext().become(aborted); - } - - private void sendToParentsButSender(AbortMessage message) { - context.parentsOf(request) - .stream() - .filter(this::isNotSender) - .forEach(actor -> actor.tell(message, self())); - } - - private void sendToChildrenButSender(AbortMessage message) { - context.childrenOf(request) - .stream() - .filter(this::isNotSender) - .forEach(actor -> actor.tell(message, self())); - } - - private boolean isNotSender(ActorRef actor) { - return !actor.equals(sender()); - } - - private void onTransactRecovery(TransactionRecoveryMessage message) { - getContext().become(receiveBuilder() - .match(TransactMessage.class, m -> onTransaction(m, message::response)) - .match(CompensationRecoveryMessage.class, m -> getContext().become(aborted)) - .build() - ); - } - - private void onAbortRecovery(AbortRecoveryMessage message) { - getContext().become( - receiveBuilder() - .match(TransactMessage.class, m -> onAbort(new AbortMessage(message.response()))) - .build()); - } - - private void onTransaction(TransactMessage message, Supplier responseSupplier) { - log().debug("{}: received transaction message of {}", request.id(), message.request()); - if (context.parentsOf(request).contains(sender())) { - parentResponses.add(message.response()); - } - - if (parentResponses.size() == context.parentsOf(request).size()) { - transact(responseSupplier); - } - } - - private void transact(Supplier responseSupplier) { - try { - if (isChosenChild(parentResponses)) { - SagaResponse sagaResponse = responseSupplier.get(); - sendToChildren(new TransactMessage(request, sagaResponse)); - getContext().become(transacted); - } else { - sendToChildren(new TransactMessage(request, SagaResponse.NONE_RESPONSE)); - getContext().become(aborted); - } - } catch (SagaStartFailedException e) { - sendToParents(new FailMessage(e)); - } catch (Exception e) { - log().error("Failed to run operation {} with error {}", request.transaction(), e); - - Message abortMessage = new AbortMessage(new TransactionFailedException(e)); - sendToParents(abortMessage); - sendToChildren(abortMessage); - getContext().become(aborted); - } - } - - private void sendToParents(Message message) { - context.parentsOf(request).forEach(actor -> actor.tell(message, self())); - } - - private void sendToChildren(Message message) { - context.childrenOf(request).forEach(actor -> actor.tell(message, self())); - } - - private boolean isChosenChild(List parentResponses) { - return request.parents().length == 0 || parentResponses.isEmpty() || parentResponses.stream() - .map(context::chosenChildren) - .anyMatch(chosenChildren -> chosenChildren.isEmpty() || chosenChildren.contains(request.id())); - } - - private SagaResponse responseOf(List responseContexts) { - if (responseContexts.isEmpty()) { - return SagaResponse.EMPTY_RESPONSE; - } - - if (responseContexts.size() == 1) { - return responseContexts.get(0); - } - return new CompositeSagaResponse(responseContexts); - } - - private ReceiveBuilder onReceive(Consumer requestConsumer) { - return receiveBuilder() - .match(CompensateMessage.class, message -> onCompensate(message, requestConsumer)); - } - - private void onCompensate(CompensateMessage message, Consumer requestConsumer) { - log().debug("{}: received compensation message from {}", request.id(), sender()); - compensatedChildren.add(sender()); - - if (compensatedChildren.size() == context.childrenOf(request).size()) { - requestConsumer.accept(request); - sendToParents(message); - } - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActorBuilder.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActorBuilder.java deleted file mode 100644 index 5004b4ecc..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActorBuilder.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import java.util.Map; -import java.util.Set; - -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaTask; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; - -public class RequestActorBuilder { - private final ActorSystem actorSystem; - private final FromJsonFormat> childrenExtractor; - - RequestActorBuilder( - ActorSystem actorSystem, - FromJsonFormat> childrenExtractor) { - - this.actorSystem = actorSystem; - this.childrenExtractor = childrenExtractor; - } - - public RequestActorContext build(SagaRequest[] requests, Map tasks, ActorRef sagaActor) { - RequestActorContext context = new RequestActorContext(childrenExtractor); - - ActorRef rootActor = rootActor(context, tasks); - ActorRef leafActor = leafActor(context, tasks); - - createRequestActors(requests, tasks, context); - - linkActorsById(rootActor, requests, context); - addLeafToChildless(leafActor, requests, context); - - context.addParent(NoOpSagaRequest.SAGA_START_REQUEST.id(), sagaActor); - context.addChild(NoOpSagaRequest.SAGA_END_REQUEST.id(), sagaActor); - return context; - } - - private void linkActorsById(ActorRef rootActor, SagaRequest[] requests, RequestActorContext context) { - for (SagaRequest request : requests) { - if (isOrphan(request)) { - context.addParent(request.id(), rootActor); - context.addChild(NoOpSagaRequest.SAGA_START_REQUEST.id(), context.actorOf(request.id())); - } else { - for (String parent : request.parents()) { - context.addParent(request.id(), context.actorOf(parent)); - context.addChild(parent, context.actorOf(request.id())); - } - } - } - } - - private boolean isOrphan(SagaRequest request) { - return request.parents().length == 0; - } - - private void createRequestActors(SagaRequest[] requests, Map tasks, RequestActorContext context) { - for (SagaRequest request : requests) { - Props props = RequestActor.props(context, tasks.get(request.task()), request); - context.addActor(request.id(), actorSystem.actorOf(props)); - } - } - - private void addLeafToChildless(ActorRef leafActor, SagaRequest[] requests, RequestActorContext context) { - for (SagaRequest request : requests) { - if (context.childrenOf(request).isEmpty()) { - context.addParent(NoOpSagaRequest.SAGA_END_REQUEST.id(), context.actorOf(request.id())); - context.addChild(request.id(), leafActor); - } - } - } - - private ActorRef rootActor(RequestActorContext context, Map tasks) { - Props root = RequestActor.props(context, tasks.get( - NoOpSagaRequest.SAGA_START_REQUEST.task()), NoOpSagaRequest.SAGA_START_REQUEST); - ActorRef actor = actorSystem.actorOf(root); - context.addActor(NoOpSagaRequest.SAGA_START_REQUEST.id(), actor); - return actor; - } - - private ActorRef leafActor(RequestActorContext context, Map tasks) { - Props leaf = RequestActor.props(context, tasks.get( - NoOpSagaRequest.SAGA_END_REQUEST.task()), NoOpSagaRequest.SAGA_END_REQUEST); - ActorRef actor = actorSystem.actorOf(leaf); - context.addActor(NoOpSagaRequest.SAGA_END_REQUEST.id(), actor); - return actor; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActorContext.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActorContext.java deleted file mode 100644 index 2e3149d40..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/RequestActorContext.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import static java.util.Collections.emptyList; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; - -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import akka.actor.ActorRef; - -class RequestActorContext { - private final Map actors; - private final Map> parents; - private final Map> children; - private final FromJsonFormat> childrenExtractor; - - RequestActorContext( - FromJsonFormat> childrenExtractor) { - this.actors = new HashMap<>(); - this.children = new HashMap<>(); - this.parents = new HashMap<>(); - this.childrenExtractor = childrenExtractor; - } - - void addActor(String id, ActorRef actorRef) { - actors.put(id, actorRef); - } - - void addChild(String requestId, ActorRef ref) { - children.computeIfAbsent(requestId, k -> new ArrayList<>()).add(ref); - } - - void addParent(String requestId, ActorRef ref) { - parents.computeIfAbsent(requestId, k -> new ArrayList<>()).add(ref); - } - - ActorRef actorOf(String id) { - return actors.get(id); - } - - Collection parentsOf(SagaRequest request) { - return parents.getOrDefault(request.id(), emptyList()); - } - - Collection childrenOf(SagaRequest request) { - return children.getOrDefault(request.id(), emptyList()); - } - - void forAll(Consumer consumer) { - actors.values() - .stream() - .forEach(consumer); - } - - Set chosenChildren(SagaResponse response) { - return childrenExtractor.fromJson(response.body()); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/AbortMessage.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/AbortMessage.java deleted file mode 100644 index f23a0790d..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/AbortMessage.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors.messages; - -import org.apache.servicecomb.saga.core.FailedSagaResponse; -import org.apache.servicecomb.saga.core.SagaResponse; - -public class AbortMessage implements Message { - private final SagaResponse response; - - public AbortMessage(Throwable e) { - response = new FailedSagaResponse(e); - } - - public AbortMessage(SagaResponse response) { - this.response = response; - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/AbortRecoveryMessage.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/AbortRecoveryMessage.java deleted file mode 100644 index 951157d29..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/AbortRecoveryMessage.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors.messages; - -import org.apache.servicecomb.saga.core.SagaResponse; - -public class AbortRecoveryMessage implements Message { - - private final SagaResponse response; - - public AbortRecoveryMessage(SagaResponse response) { - this.response = response; - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/CompensateMessage.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/CompensateMessage.java deleted file mode 100644 index 5fd07019b..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/CompensateMessage.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors.messages; - -import org.apache.servicecomb.saga.core.SagaResponse; - -public class CompensateMessage implements Message { - private final SagaResponse response; - - public CompensateMessage(SagaResponse response) { - this.response = response; - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/CompensationRecoveryMessage.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/CompensationRecoveryMessage.java deleted file mode 100644 index 421a0928a..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/CompensationRecoveryMessage.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors.messages; - -public class CompensationRecoveryMessage implements Message { - -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/FailMessage.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/FailMessage.java deleted file mode 100644 index 7a80ecb66..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/FailMessage.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors.messages; - -import org.apache.servicecomb.saga.core.FailedSagaResponse; -import org.apache.servicecomb.saga.core.SagaResponse; - -public class FailMessage implements Message { - private final SagaResponse response; - - public FailMessage(Throwable e) { - response = new FailedSagaResponse(e); - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/Message.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/Message.java deleted file mode 100644 index 3ed818765..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/Message.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors.messages; - -public interface Message { -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/TransactMessage.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/TransactMessage.java deleted file mode 100644 index e4c57a28b..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/TransactMessage.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors.messages; - -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; - -public class TransactMessage implements Message { - private final SagaRequest request; - private final SagaResponse response; - - public TransactMessage(SagaRequest request, SagaResponse response) { - this.request = request; - this.response = response; - } - - public SagaRequest request() { - return request; - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/TransactionRecoveryMessage.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/TransactionRecoveryMessage.java deleted file mode 100644 index 26ba05b89..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/actors/messages/TransactionRecoveryMessage.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors.messages; - -import org.apache.servicecomb.saga.core.SagaResponse; - -public class TransactionRecoveryMessage implements Message { - private final SagaResponse response; - - public TransactionRecoveryMessage(SagaResponse response) { - this.response = response; - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/SagaExecutionComponent.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/SagaExecutionComponent.java deleted file mode 100644 index 7a600d7e3..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/SagaExecutionComponent.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.application; - -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; - -import org.apache.servicecomb.saga.core.EventEnvelope; -import org.apache.servicecomb.saga.core.EventStore; -import org.apache.servicecomb.saga.core.Saga; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.ToJsonFormat; -import org.apache.servicecomb.saga.core.PersistentStore; -import org.apache.servicecomb.saga.core.SagaDefinition; -import org.apache.servicecomb.saga.core.SagaEvent; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import org.apache.servicecomb.saga.infrastructure.EmbeddedEventStore; -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class SagaExecutionComponent { - - private final PersistentStore persistentStore; - private final FromJsonFormat fromJsonFormat; - private final ToJsonFormat toJsonFormat; - private final SagaFactory sagaFactory; - - public SagaExecutionComponent( - PersistentStore persistentStore, - FromJsonFormat fromJsonFormat, - ToJsonFormat toJsonFormat, - SagaFactory sagaFactory) { - this.persistentStore = persistentStore; - this.fromJsonFormat = fromJsonFormat; - this.toJsonFormat = toJsonFormat; - this.sagaFactory = sagaFactory; - } - - @Segment(name = "runSagaExecutionComponent", category = "application", library = "kamon") - public SagaResponse run(String requestJson) { - String sagaId = UUID.randomUUID().toString(); - EventStore sagaLog = new EmbeddedEventStore(); - SagaDefinition definition = fromJsonFormat.fromJson(requestJson); - Saga saga = sagaFactory.createSaga(requestJson, sagaId, sagaLog, definition); - return saga.run(); - } - - public void reanimate() { - Map> pendingSagaEvents = persistentStore.findPendingSagaEvents(); - - for (Entry> entry : pendingSagaEvents.entrySet()) { - EventStore eventStore = new EmbeddedEventStore(); - eventStore.populate(entry.getValue()); - SagaEvent event = entry.getValue().iterator().next().event; - - String requestJson = event.json(toJsonFormat); - SagaDefinition definition = fromJsonFormat.fromJson(requestJson); - - Saga saga = sagaFactory.createSaga(requestJson, event.sagaId, eventStore, definition); - - saga.play(); - saga.run(); - } - } - - public void terminate() throws Exception { - sagaFactory.terminate(); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/SagaFactory.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/SagaFactory.java deleted file mode 100644 index b60b5e741..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/SagaFactory.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.application; - -import org.apache.servicecomb.saga.core.EventStore; -import org.apache.servicecomb.saga.core.Saga; -import org.apache.servicecomb.saga.core.SagaDefinition; - -public interface SagaFactory { - Saga createSaga(String requestJson, String sagaId, EventStore sagaLog, SagaDefinition definition); - - boolean isTerminated(); - - void terminate() throws Exception; -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/interpreter/FromJsonFormat.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/interpreter/FromJsonFormat.java deleted file mode 100644 index ccfb40826..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/interpreter/FromJsonFormat.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.application.interpreter; - -public interface FromJsonFormat { - - T fromJson(String requestJson); - -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/interpreter/RestRequestChecker.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/interpreter/RestRequestChecker.java deleted file mode 100644 index 7a65e48ce..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/application/interpreter/RestRequestChecker.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.application.interpreter; - -import static java.util.Arrays.asList; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class RestRequestChecker { - - private static final Set validMethods = new HashSet<>(asList( - "GET", - "POST", - "PUT", - "DELETE" - )); - - private RestRequestChecker() { - } - - public static void checkParameters(String method, Map> params) { - if (method == null || !validMethods.contains(method.toUpperCase())) { - throw new IllegalArgumentException("Unsupported method " + method); - } - - if (isDeleteOrGet(method) && hasBody(params)) { - throw new IllegalArgumentException("GET & DELETE request cannot enclose a body"); - } - } - - private static boolean isDeleteOrGet(String method) { - return "GET".equalsIgnoreCase(method) || "DELETE".equalsIgnoreCase(method); - } - - private static boolean hasBody(Map> params) { - return params != null && (params.containsKey("form") || params.containsKey("json")); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/ByLevelTraveller.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/ByLevelTraveller.java deleted file mode 100644 index 22bc87487..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/ByLevelTraveller.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class ByLevelTraveller implements Traveller { - - private final Collection> nodes; - private final Collection> nodesBuffer; - - private final Queue> nodesWithoutParent = new LinkedList<>(); - private final Map>> nodeParents = new HashMap<>(); - private final TraversalDirection traversalDirection; - - - public ByLevelTraveller(SingleLeafDirectedAcyclicGraph dag, TraversalDirection traversalDirection) { - this.nodes = new LinkedHashSet<>(); - this.nodesBuffer = new LinkedList<>(); - this.traversalDirection = traversalDirection; - - nodesWithoutParent.offer(traversalDirection.root(dag)); - } - - @Segment(name = "travelNext", category = "application", library = "kamon") - @Override - public void next() { - nodes.addAll(nodesBuffer); - nodesBuffer.clear(); - boolean buffered = false; - - while (!nodesWithoutParent.isEmpty() && !buffered) { - Node node = nodesWithoutParent.poll(); - nodes.add(node); - - for (Node child : traversalDirection.children(node)) { - nodeParents.computeIfAbsent(child.id(), id -> new HashSet<>(traversalDirection.parents(child))); - nodeParents.get(child.id()).remove(node); - - if (nodeParents.get(child.id()).isEmpty()) { - nodesWithoutParent.offer(child); - nodesBuffer.add(child); - buffered = true; - } - } - } - } - - @Override - public boolean hasNext() { - return !nodesWithoutParent.isEmpty(); - } - - @Override - public Collection> nodes() { - return nodes; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/FromLeafTraversalDirection.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/FromLeafTraversalDirection.java deleted file mode 100644 index d97c40fca..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/FromLeafTraversalDirection.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.Set; - -public class FromLeafTraversalDirection implements TraversalDirection { - - @Override - public Node root(SingleLeafDirectedAcyclicGraph dag) { - return dag.leaf(); - } - - @Override - public Set> parents(Node node) { - return node.children(); - } - - @Override - public Set> children(Node node) { - return node.parents(); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/FromRootTraversalDirection.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/FromRootTraversalDirection.java deleted file mode 100644 index 8c664ac5d..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/FromRootTraversalDirection.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.Set; - -public class FromRootTraversalDirection implements TraversalDirection { - - @Override - public Node root(SingleLeafDirectedAcyclicGraph dag) { - return dag.root(); - } - - @Override - public Set> parents(Node node) { - return node.parents(); - } - - @Override - public Set> children(Node node) { - return node.children(); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphBasedSagaFactory.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphBasedSagaFactory.java deleted file mode 100644 index 2048383f1..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphBasedSagaFactory.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.Set; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.servicecomb.saga.core.EventStore; -import org.apache.servicecomb.saga.core.GraphBasedSaga; -import org.apache.servicecomb.saga.core.Saga; -import org.apache.servicecomb.saga.core.SagaContext; -import org.apache.servicecomb.saga.core.SagaContextImpl; -import org.apache.servicecomb.saga.core.application.SagaFactory; -import org.apache.servicecomb.saga.infrastructure.ContextAwareEventStore; -import org.apache.servicecomb.saga.core.PersistentStore; -import org.apache.servicecomb.saga.core.SagaDefinition; -import org.apache.servicecomb.saga.core.SagaTaskFactory; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; - -public class GraphBasedSagaFactory implements SagaFactory { - private final AtomicBoolean isRunning = new AtomicBoolean(true); - private final FromJsonFormat> childrenExtractor; - private final Executor executorService; - private final GraphBuilder graphBuilder; - private final SagaTaskFactory sagaTaskFactory; - - public GraphBasedSagaFactory(int retryDelay, - PersistentStore persistentStore, - FromJsonFormat> childrenExtractor, - ExecutorService executorService) { - - this.childrenExtractor = childrenExtractor; - this.executorService = executorService; - this.sagaTaskFactory = new SagaTaskFactory(retryDelay, persistentStore); - this.graphBuilder = new GraphBuilder(new GraphCycleDetectorImpl<>()); - } - - @Override - public Saga createSaga(String requestJson, String sagaId, EventStore sagaLog, SagaDefinition definition) { - SagaContext sagaContext = new SagaContextImpl(childrenExtractor); - - return new GraphBasedSaga( - sagaLog, - executorService, - sagaTaskFactory.sagaTasks(sagaId, - requestJson, - definition.policy(), - new ContextAwareEventStore(sagaLog, sagaContext) - ), - sagaContext, - graphBuilder.build(definition.requests())); - } - - @Override - public boolean isTerminated() { - return !isRunning.get(); - } - - @Override - public void terminate() throws Exception { - isRunning.compareAndSet(true, false); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphBuilder.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphBuilder.java deleted file mode 100644 index 578cbb9b4..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphBuilder.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.SagaException; -import org.apache.servicecomb.saga.core.SagaRequest; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class GraphBuilder { - - private final GraphCycleDetector detector; - - public GraphBuilder(GraphCycleDetector detector) { - this.detector = detector; - } - - @Segment(name = "buildGraph", category = "application", library = "kamon") - public SingleLeafDirectedAcyclicGraph build(SagaRequest[] sagaRequests) { - Map> requestNodes = requestsToNodes(sagaRequests); - - SingleLeafDirectedAcyclicGraph graph = linkNodesToGraph(sagaRequests, requestNodes); - detectCycle(graph); - return graph; - } - - private SingleLeafDirectedAcyclicGraph linkNodesToGraph( - SagaRequest[] sagaRequests, - Map> requestNodes) { - - Node root = rootNode(0); - Node leaf = leafNode(sagaRequests.length + 1); - - for (SagaRequest sagaRequest : sagaRequests) { - if (isOrphan(sagaRequest)) { - root.addChild(requestNodes.get(sagaRequest.id())); - } else { - for (String parent : sagaRequest.parents()) { - requestNodes.get(parent).addChild(requestNodes.get(sagaRequest.id())); - } - } - } - - requestNodes.values().stream() - .filter((node) -> node.children().isEmpty()) - .forEach(node -> node.addChild(leaf)); - - return new SingleLeafDirectedAcyclicGraph<>(root, leaf); - } - - private Node rootNode(int id) { - return new Node<>( - id, - NoOpSagaRequest.SAGA_START_REQUEST); - } - - private Node leafNode(int id) { - return new Node<>( - id, - NoOpSagaRequest.SAGA_END_REQUEST); - } - - private boolean isOrphan(SagaRequest sagaRequest) { - return sagaRequest.parents().length == 0; - } - - private Map> requestsToNodes(SagaRequest[] sagaRequests) { - long index = 1; - Map> requestMap = new HashMap<>(); - for (SagaRequest sagaRequest : sagaRequests) { - if (requestMap.containsKey(sagaRequest.id())) { - // TODO: 8/20/2017 add random id if user didn't provide one - throw new SagaException("Failed to interpret requests with duplicate request id: " + sagaRequest.id()); - } - requestMap.put(sagaRequest.id(), new Node<>(index++, sagaRequest)); - } - return requestMap; - } - - private void detectCycle(SingleLeafDirectedAcyclicGraph graph) { - Set> jointNodes = detector.cycleJoints(graph); - - if (!jointNodes.isEmpty()) { - throw new SagaException("Cycle detected in the request graph at nodes " + jointNodes); - } - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetector.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetector.java deleted file mode 100644 index 9b12bc887..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetector.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.Set; - -public interface GraphCycleDetector { - - Set> cycleJoints(SingleLeafDirectedAcyclicGraph graph); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetectorImpl.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetectorImpl.java deleted file mode 100644 index 6011a98d5..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetectorImpl.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Queue; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Cycle detection is based on topological sort with Kahn's algorithm. - * - * @see Topological Sorting - */ -public class GraphCycleDetectorImpl implements GraphCycleDetector { - - @Override - public Set> cycleJoints(SingleLeafDirectedAcyclicGraph graph) { - Queue> orphanNodes = new LinkedList<>(); - Map, Set>> nodeParents = new HashMap<>(); - - orphanNodes.add(graph.root()); - - traverse(orphanNodes, nodeParents); - - return unvisitedNodes(nodeParents); - } - - private void traverse(Queue> orphanNodes, Map, Set>> nodeParents) { - while (!orphanNodes.isEmpty()) { - Node node = orphanNodes.poll(); - - node.children().forEach(child -> { - nodeParents.computeIfAbsent(child, n -> new HashSet<>(child.parents())) - .remove(node); - - if (nodeParents.get(child).isEmpty()) { - orphanNodes.add(child); - } - }); - } - } - - private Set> unvisitedNodes(Map, Set>> nodeParents) { - return nodeParents.entrySet() - .parallelStream() - .filter(parents -> !parents.getValue().isEmpty()) - .map(Entry::getKey) - .collect(Collectors.toSet()); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/Node.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/Node.java deleted file mode 100644 index 0b3be0a33..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/Node.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -public class Node { - private final long id; - private final T value; - private final Set> children = new HashSet<>(); - private final Set> parents = new HashSet<>(); - - public Node(long id, T value) { - this.id = id; - this.value = value; - } - - long id() { - return id; - } - - public T value() { - return value; - } - - Set> parents() { - return parents; - } - - public Set> children() { - return children; - } - - public void addChild(Node node) { - children.add(node); - node.parents.add(this); - } - - public void addChildren(Collection> nodes) { - children.addAll(nodes); - nodes.forEach(node -> node.parents.add(this)); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Node node = (Node) o; - return id == node.id; - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - - @Override - public String toString() { - return "Node{" + - "id=" + id + - ", value=" + value + - '}'; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/SingleLeafDirectedAcyclicGraph.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/SingleLeafDirectedAcyclicGraph.java deleted file mode 100644 index cf0d19b15..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/SingleLeafDirectedAcyclicGraph.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -public class SingleLeafDirectedAcyclicGraph { - - private final Node root; - private final Node leaf; - - public SingleLeafDirectedAcyclicGraph(Node root, Node leaf) { - - this.root = root; - this.leaf = leaf; - } - - public Node root() { - return root; - } - - Node leaf() { - return leaf; - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/Traveller.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/Traveller.java deleted file mode 100644 index e44848be6..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/Traveller.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.Collection; - -public interface Traveller { - - void next(); - - boolean hasNext(); - - Collection> nodes(); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/TraversalDirection.java b/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/TraversalDirection.java deleted file mode 100644 index 22f734316..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/core/dag/TraversalDirection.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.Set; - -public interface TraversalDirection { - - Node root(SingleLeafDirectedAcyclicGraph dag); - - Set> parents(Node node); - - Set> children(Node node); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/infrastructure/ContextAwareEventStore.java b/saga-core/src/main/java/org/apache/servicecomb/saga/infrastructure/ContextAwareEventStore.java deleted file mode 100644 index 40fa71d1a..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/infrastructure/ContextAwareEventStore.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.infrastructure; - -import java.util.Iterator; - -import org.apache.servicecomb.saga.core.EventEnvelope; -import org.apache.servicecomb.saga.core.EventStore; -import org.apache.servicecomb.saga.core.SagaContext; -import org.apache.servicecomb.saga.core.SagaEvent; - -public class ContextAwareEventStore implements EventStore { - private final EventStore eventStore; - private final SagaContext sagaContext; - - public ContextAwareEventStore(EventStore eventStore, SagaContext sagaContext) { - this.eventStore = eventStore; - this.sagaContext = sagaContext; - } - - @Override - public void offer(SagaEvent sagaEvent) { - sagaEvent.gatherTo(sagaContext); - eventStore.offer(sagaEvent); - } - - @Override - public void populate(Iterable events) { - eventStore.populate(events); - } - - @Override - public long size() { - return eventStore.size(); - } - - @Override - public Iterator iterator() { - return eventStore.iterator(); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/infrastructure/EmbeddedEventStore.java b/saga-core/src/main/java/org/apache/servicecomb/saga/infrastructure/EmbeddedEventStore.java deleted file mode 100644 index d3422643e..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/infrastructure/EmbeddedEventStore.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.infrastructure; - -import java.lang.invoke.MethodHandles; -import java.util.Iterator; -import java.util.Queue; -import java.util.concurrent.LinkedBlockingQueue; - -import org.apache.servicecomb.saga.core.EventEnvelope; -import org.apache.servicecomb.saga.core.EventStore; -import org.apache.servicecomb.saga.core.SagaEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EmbeddedEventStore implements EventStore { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private final Queue events = new LinkedBlockingQueue<>(); - - @Override - public void offer(SagaEvent sagaEvent) { - events.offer(sagaEvent); - log.info("Added event {}", sagaEvent); - } - - @Override - public void populate(Iterable events) { - for (EventEnvelope event : events) { - this.events.offer(event.event); - log.info("Populated event {}", event); - } - } - - @Override - public long size() { - return events.size(); - } - - @Override - public Iterator iterator() { - return events.iterator(); - } -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/transports/RestTransport.java b/saga-core/src/main/java/org/apache/servicecomb/saga/transports/RestTransport.java deleted file mode 100644 index 3d5bda390..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/transports/RestTransport.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.transports; - -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.Transport; -import java.util.Map; - -public interface RestTransport extends Transport { - - SagaResponse with(String address, String path, String method, Map> params); -} diff --git a/saga-core/src/main/java/org/apache/servicecomb/saga/transports/TransportFactory.java b/saga-core/src/main/java/org/apache/servicecomb/saga/transports/TransportFactory.java deleted file mode 100644 index b34b5bdf7..000000000 --- a/saga-core/src/main/java/org/apache/servicecomb/saga/transports/TransportFactory.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.transports; - -public interface TransportFactory { - - RestTransport restTransport(); -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/BackwardRecoveryTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/BackwardRecoveryTest.java deleted file mode 100644 index 4f0399287..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/BackwardRecoveryTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Before; -import org.junit.Test; - -public class BackwardRecoveryTest { - - private final String serviceName = "aaa"; - private final Transaction transaction = mock(Transaction.class); - private final SagaTask sagaTask = mock(SagaTask.class); - private final SagaRequest sagaRequest = mock(SagaRequest.class); - private final SagaResponse parentResponse = mock(SagaResponse.class); - private final BackwardRecovery backwardRecovery = new BackwardRecovery(); - private final RuntimeException exception = new RuntimeException("oops"); - - @Before - public void setUp() throws Exception { - when(sagaRequest.serviceName()).thenReturn(serviceName); - when(sagaRequest.transaction()).thenReturn(transaction); - } - - @Test - public void blowsUpWhenTaskIsNotCommitted() { - doThrow(exception).when(transaction).send(serviceName, parentResponse); - - try { - backwardRecovery.apply(sagaTask, sagaRequest, parentResponse); - expectFailing(RuntimeException.class); - } catch (RuntimeException ignored) { - } - - verify(sagaTask).abort(sagaRequest, exception); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/CompensationImpl.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/CompensationImpl.java deleted file mode 100644 index c974bc427..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/CompensationImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.util.Map; - -public class CompensationImpl extends RestOperation implements Compensation { - - public CompensationImpl(String path, String method, Map> params) { - super(path, method, params); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/CompositeSagaLogTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/CompositeSagaLogTest.java deleted file mode 100644 index c7dea517d..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/CompositeSagaLogTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import org.junit.Test; - -public class CompositeSagaLogTest { - - private final SagaRequest request = mock(SagaRequest.class); - private final DummyEvent sagaEvent = new DummyEvent(request); - private final SagaLog embedded = mock(SagaLog.class); - private final SagaLog persistent = mock(SagaLog.class); - - private final SagaLog compositeSagaLog = new CompositeSagaLog(embedded, persistent); - - @Test - public void addsLogsToEmbeddedOnlyAfterPersisted() { - doThrow(RuntimeException.class).when(persistent).offer(sagaEvent); - - try { - compositeSagaLog.offer(sagaEvent); - expectFailing(RuntimeException.class); - } catch (RuntimeException ignored) { - } - - verify(embedded, never()).offer(sagaEvent); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/CompositeSagaResponseTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/CompositeSagaResponseTest.java deleted file mode 100644 index be4b9f4de..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/CompositeSagaResponseTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static java.util.Arrays.asList; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; - -import org.junit.Test; -import org.mockito.Mockito; - -public class CompositeSagaResponseTest { - - private final SagaResponse response1 = Mockito.mock(SagaResponse.class); - private final SagaResponse response2 = Mockito.mock(SagaResponse.class); - - private final SagaResponse compositeSagaResponse = new CompositeSagaResponse(asList(response1, response2)); - - @Test - public void succeededOnlyWhenAllAreSuccessful() throws Exception { - when(response1.succeeded()).thenReturn(true); - when(response2.succeeded()).thenReturn(true); - - assertThat(compositeSagaResponse.succeeded(), is(true)); - } - - @Test - public void failedWhenAnyIsNotSuccessful() throws Exception { - when(response1.succeeded()).thenReturn(true); - when(response2.succeeded()).thenReturn(false); - - assertThat(compositeSagaResponse.succeeded(), is(false)); - } - - @Test - public void bodyCombinesAllResponseBodies() throws Exception { - when(response1.body()).thenReturn("{\n" - + " \"status\": 500,\n" - + " \"body\" : \"oops\"\n" - + "}\n"); - - when(response2.body()).thenReturn("{\n" - + " \"status\": 200,\n" - + " \"body\" : \"blah\"\n" - + "}\n"); - - assertThat(compositeSagaResponse.body(), is("[{\n" - + " \"status\": 500,\n" - + " \"body\" : \"oops\"\n" - + "}\n" - + ", {\n" - + " \"status\": 200,\n" - + " \"body\" : \"blah\"\n" - + "}\n" - + "]")); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/DummyEvent.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/DummyEvent.java deleted file mode 100644 index c775afe50..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/DummyEvent.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class DummyEvent extends SagaEvent { - - DummyEvent(SagaRequest payload) { - super("0", payload); - } - - @Override - public void gatherTo(EventContext sagaContext) { - - } - -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/FallbackPolicyTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/FallbackPolicyTest.java deleted file mode 100644 index a2d1f32b6..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/FallbackPolicyTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class FallbackPolicyTest { - - private final int numberOfRetries = 3; - private final String address = uniquify("address"); - - private final SagaResponse success = Mockito.mock(SagaResponse.class); - private final SagaResponse failure = Mockito.mock(SagaResponse.class); - private final Fallback fallback = Mockito.mock(Fallback.class); - private final Compensation compensation = Mockito.mock(Compensation.class); - private final FallbackPolicy fallbackPolicy = new FallbackPolicy(100); - - @SuppressWarnings("ThrowableInstanceNeverThrown") - private final RuntimeException exception = new RuntimeException("oops"); - - @Before - public void setUp() throws Exception { - when(compensation.retries()).thenReturn(numberOfRetries); - when(fallback.send(address)).thenReturn(failure); - } - - @Test - public void retriesTransportForSpecifiedTimes() { - when(compensation.send(address)) - .thenThrow(exception) - .thenThrow(exception) - .thenReturn(success); - - SagaResponse response = fallbackPolicy.apply(address, compensation, fallback); - - assertThat(response, is(success)); - verify(compensation, times(3)).send(address); - } - - @Test - public void fallbackIfTransportFailedWithRetry() { - when(compensation.send(address)).thenThrow(exception); - - SagaResponse response = fallbackPolicy.apply(address, compensation, fallback); - assertThat(response, is(failure)); - - verify(compensation, times(numberOfRetries + 1)).send(address); - verify(fallback).send(address); - } - - @Test - public void retryUntilSuccessIfNumberOfRetriesIsNegative() throws InterruptedException { - reset(compensation); - when(compensation.retries()).thenReturn(-1); - when(compensation.send(address)) - .thenThrow(exception, exception, exception, exception, exception) - .thenReturn(success); - - SagaResponse response = fallbackPolicy.apply(address, compensation, fallback); - - assertThat(response, is(success)); - verify(fallback, never()).send(anyString()); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/ForwardRecoveryTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/ForwardRecoveryTest.java deleted file mode 100644 index e7651701f..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/ForwardRecoveryTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Before; -import org.junit.Test; - -public class ForwardRecoveryTest { - - private final SagaTask sagaTask = mock(SagaTask.class); - - private final Transaction transaction = mock(Transaction.class); - private final SagaRequest sagaRequest = mock(SagaRequest.class); - private final SagaResponse parentResponse = mock(SagaResponse.class); - - private final ForwardRecovery forwardRecovery = new ForwardRecovery(); - - private final String serviceName = "aaa"; - - @Before - public void setUp() throws Exception { - when(sagaRequest.serviceName()).thenReturn(serviceName); - when(sagaRequest.transaction()).thenReturn(transaction); - when(sagaRequest.failRetryDelayMilliseconds()).thenReturn(300); - } - - @Test - public void blowsUpWhenTaskIsNotCommittedWithFailRetryDelaySeconds() throws Exception { - doThrow(Exception.class).when(transaction).send(serviceName, parentResponse); - - Thread t = new Thread(() -> forwardRecovery.apply(sagaTask, sagaRequest, parentResponse)); - t.start(); - Thread.sleep(400); - t.interrupt(); - - verify(transaction, times(2)).send(serviceName, parentResponse); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/LongIdGeneratorTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/LongIdGeneratorTest.java deleted file mode 100644 index 775866b63..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/LongIdGeneratorTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; - -public class LongIdGeneratorTest { - - - private final LongIdGenerator generator = new LongIdGenerator(); - - @Test - public void generatesLongInSequence() { - for (long index = 0; index < 10; index++) { - assertThat(generator.nextId(), is(index + 1)); - } - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/RestOperationTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/RestOperationTest.java deleted file mode 100644 index 7f1990d15..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/RestOperationTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; - -public class RestOperationTest { - - @Test - public void blowsUpWhenGetMethodWithForm() { - try { - new RestOperation("blah", "GET", singletonMap("form", emptyMap())); - expectFailing(IllegalArgumentException.class); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("GET & DELETE request cannot enclose a body")); - } - } - - @Test - public void blowsUpWhenGetMethodWithJson() { - try { - new RestOperation("blah", "GET", singletonMap("json", emptyMap())); - expectFailing(IllegalArgumentException.class); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("GET & DELETE request cannot enclose a body")); - } - } - - @Test - public void blowsUpWhenDeleteMethodWithForm() { - try { - new RestOperation("blah", "DELETE", singletonMap("form", emptyMap())); - expectFailing(IllegalArgumentException.class); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("GET & DELETE request cannot enclose a body")); - } - } - - @Test - public void blowsUpWhenDeleteMethodWithJson() { - try { - new RestOperation("blah", "DELETE", singletonMap("json", emptyMap())); - expectFailing(IllegalArgumentException.class); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("GET & DELETE request cannot enclose a body")); - } - } - - @Test - public void blowsUpWhenMethodIsNotSupported() { - try { - new RestOperation("blah", "foo", emptyMap()); - expectFailing(IllegalArgumentException.class); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("Unsupported method foo")); - } - } - - @Test - public void blowsUpWhenMethodIsNull() { - try { - new RestOperation("blah", null, emptyMap()); - expectFailing(IllegalArgumentException.class); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("Unsupported method null")); - } - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/RetrySagaLogTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/RetrySagaLogTest.java deleted file mode 100644 index 6da8f16e9..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/RetrySagaLogTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - - -import static org.awaitility.Awaitility.await; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import org.junit.Test; - -import org.apache.servicecomb.saga.core.SagaTaskFactory.RetrySagaLog; - -public class RetrySagaLogTest { - - private final PersistentStore persistentStore = mock(PersistentStore.class); - private final SagaRequest sagaRequest = mock(SagaRequest.class); - private final SagaEvent dummyEvent = new DummyEvent(sagaRequest); - private final RetrySagaLog retrySagaLog = new RetrySagaLog(persistentStore, 100); - - private volatile boolean interrupted = false; - - @Test - public void retryUntilSuccessWhenEventIsNotPersisted() throws InterruptedException { - doThrow(RuntimeException.class). - doThrow(RuntimeException.class). - doThrow(RuntimeException.class). - doThrow(RuntimeException.class). - doThrow(RuntimeException.class). - doNothing(). - when(persistentStore).offer(dummyEvent); - - retrySagaLog.offer(dummyEvent); - - verify(persistentStore, times(6)).offer(dummyEvent); - } - - @Test - public void exitOnInterruption() throws InterruptedException { - ExecutorService executor = Executors.newSingleThreadExecutor(); - - Future future = executor.submit(() -> { - doThrow(RuntimeException.class).when(persistentStore).offer(dummyEvent); - - retrySagaLog.offer(dummyEvent); - interrupted = true; - }); - - Thread.sleep(500); - - assertThat(future.cancel(true), is(true)); - - await().atMost(2, TimeUnit.SECONDS).until(() -> interrupted); - executor.shutdown(); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaEndTaskTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaEndTaskTest.java deleted file mode 100644 index 22f5fa15e..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaEndTaskTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -public class SagaEndTaskTest { - private final SagaRequest request = mock(SagaRequest.class); - private final SagaLog sagaLog = mock(SagaLog.class); - - private final String sagaId = "0"; - private final SagaEndTask sagaEndTask = new SagaEndTask(sagaId, sagaLog); - - @Test - public void emptyResponseOnSuccessfulEventPersistence() throws Exception { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SagaEndedEvent.class); - doNothing().when(sagaLog).offer(argumentCaptor.capture()); - - sagaEndTask.commit(request, SagaResponse.EMPTY_RESPONSE); - - SagaEndedEvent event = argumentCaptor.getValue(); - assertThat(event.sagaId, is(sagaId)); - assertThat(event.json(null), is("{}")); - assertThat(event.payload(), is(request)); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaEventMatcher.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaEventMatcher.java deleted file mode 100644 index 7e8289c71..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaEventMatcher.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.util.Objects; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -public class SagaEventMatcher extends TypeSafeMatcher { - - private final String sagaId; - private final Operation operation; - private final Class aClass; - - public static Matcher eventWith(String sagaId, Operation operation, Class aClass) { - return new SagaEventMatcher(sagaId, operation, aClass); - } - - static Matcher eventWith(Operation operation, Class aClass) { - return eventWith("0", operation, aClass); - } - - private SagaEventMatcher(String sagaId, Operation operation, Class aClass) { - this.sagaId = sagaId; - this.operation = operation; - this.aClass = aClass; - } - - @Override - protected void describeMismatchSafely(SagaEvent item, Description description) { - description - .appendText("SagaEvent {sagaId=" + item.sagaId + ", operation=" + operation(item) + ", class=" + item.getClass()); - } - - @Override - protected boolean matchesSafely(SagaEvent envelope) { - return Objects.equals(envelope.sagaId, sagaId) - && operation(envelope).equals(operation) - && envelope.getClass().equals(aClass); - } - - @Override - public void describeTo(Description description) { - description - .appendText("SagaEvent {sagaId=" + sagaId + ", operation=" + operation + ", class=" + aClass.getCanonicalName()); - } - - private Operation operation(SagaEvent envelope) { - return operation instanceof Compensation ? envelope.payload().compensation() : envelope.payload().transaction(); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaExecutionComponentTestBase.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaExecutionComponentTestBase.java deleted file mode 100644 index b9e893f31..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaExecutionComponentTestBase.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static org.apache.servicecomb.saga.core.Operation.TYPE_REST; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.awaitility.Awaitility.waitAtMost; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.saga.core.application.SagaFactory; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import org.apache.servicecomb.saga.core.application.SagaExecutionComponent; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import org.apache.servicecomb.saga.infrastructure.EmbeddedEventStore; - -@SuppressWarnings("unchecked") -public abstract class SagaExecutionComponentTestBase { - private static final String requestJson = "[\n" - + " {\n" - + " \"id\": \"request-1\",\n" - + " \"serviceName\": \"aaa\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/as\"\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/as\"\n" - + " }\n" - + " }\n" - + "]\n"; - - private static final String sagaJson = "{\n" - + " \"policy\": \"ForwardRecovery\",\n" - + " \"requests\": " + requestJson + "\n" - + "}"; - - private static final String anotherRequestJson = "[\n" - + " {\n" - + " \"id\": \"request-2\",\n" - + " \"serviceName\": \"bbb\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/bs\"\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/bs\"\n" - + " }\n" - + " }\n" - + "]\n"; - - private static final String anotherSagaJson = "{\n" - + " \"policy\": \"ForwardRecovery\",\n" - + " \"requests\": " + anotherRequestJson + "\n" - + "}"; - - private final SagaRequest request1 = new SagaRequestImpl( - "request-1", - "aaa", - TYPE_REST, - new TransactionImpl("/rest/as", "post", emptyMap()), - new CompensationImpl("/rest/as", "delete", emptyMap()) - ); - - private final SagaRequest request2 = new SagaRequestImpl( - "request-2", - "bbb", - TYPE_REST, - new TransactionImpl("/rest/bs", "post", emptyMap()), - new CompensationImpl("/rest/bs", "delete", emptyMap()) - ); - - private final SagaDefinition definition1 = new SagaDefinition() { - @Override - public RecoveryPolicy policy() { - return new ForwardRecovery(); - } - - @Override - public SagaRequest[] requests() { - return new SagaRequest[]{request1}; - } - }; - - private final SagaDefinition definition2 = new SagaDefinition() { - @Override - public RecoveryPolicy policy() { - return new BackwardRecovery(); - } - - @Override - public SagaRequest[] requests() { - return new SagaRequest[]{request2}; - } - }; - - private final FromJsonFormat fromJsonFormat = Mockito.mock(FromJsonFormat.class); - private final EmbeddedPersistentStore eventStore = new EmbeddedPersistentStore(); - - private final SagaExecutionComponent coordinator = new SagaExecutionComponent( - eventStore, - fromJsonFormat, - null, - sagaFactory(eventStore) - ); - - private final String sagaId = "1"; - - @Before - public void setUp() throws Exception { - when(fromJsonFormat.fromJson(sagaJson)).thenReturn(definition1); - when(fromJsonFormat.fromJson(anotherSagaJson)).thenReturn(definition2); - } - - @Test - public void recoverSagaWithEventsFromEventStore() throws IOException { - eventStore.offer(new SagaStartedEvent(sagaId, sagaJson, NoOpSagaRequest.SAGA_START_REQUEST)); - coordinator.reanimate(); - - assertThat(eventStore, contains( - eventWith(NoOpSagaRequest.SAGA_START_REQUEST, SagaStartedEvent.class), - eventWith(request1, TransactionStartedEvent.class), - eventWith(request1, TransactionEndedEvent.class), - eventWith(NoOpSagaRequest.SAGA_END_REQUEST, SagaEndedEvent.class) - )); - } - - @Test - public void runSagaWithEventStore() throws IOException { - SagaResponse response = coordinator.run(sagaJson); - - assertThat(response, is(SagaResponse.EMPTY_RESPONSE)); - assertThat(eventStore, contains( - eventWith(NoOpSagaRequest.SAGA_START_REQUEST, SagaStartedEvent.class), - eventWith(request1, TransactionStartedEvent.class), - eventWith(request1, TransactionEndedEvent.class), - eventWith(NoOpSagaRequest.SAGA_END_REQUEST, SagaEndedEvent.class) - )); - } - - @Test - public void processRequestsInParallel() { - CompletableFuture.runAsync(() -> coordinator.run(sagaJson)); - CompletableFuture.runAsync(() -> coordinator.run(anotherSagaJson)); - - waitAtMost(2, SECONDS).until(() -> eventStore.size() == 8); - - assertThat(eventStore, containsInAnyOrder( - eventWith(NoOpSagaRequest.SAGA_START_REQUEST, SagaStartedEvent.class), - eventWith(request1, TransactionStartedEvent.class), - eventWith(request1, TransactionEndedEvent.class), - eventWith(NoOpSagaRequest.SAGA_END_REQUEST, SagaEndedEvent.class), - eventWith(NoOpSagaRequest.SAGA_START_REQUEST, SagaStartedEvent.class), - eventWith(request2, TransactionStartedEvent.class), - eventWith(request2, TransactionEndedEvent.class), - eventWith(NoOpSagaRequest.SAGA_END_REQUEST, SagaEndedEvent.class) - )); - } - - @Test - public void runSagaAfterRecovery() throws IOException { - eventStore.offer(new SagaStartedEvent(sagaId, sagaJson, NoOpSagaRequest.SAGA_START_REQUEST)); - coordinator.reanimate(); - - coordinator.run(anotherSagaJson); - - assertThat(eventStore, contains( - eventWith(NoOpSagaRequest.SAGA_START_REQUEST, SagaStartedEvent.class), - eventWith(request1, TransactionStartedEvent.class), - eventWith(request1, TransactionEndedEvent.class), - eventWith(NoOpSagaRequest.SAGA_END_REQUEST, SagaEndedEvent.class), - eventWith(NoOpSagaRequest.SAGA_START_REQUEST, SagaStartedEvent.class), - eventWith(request2, TransactionStartedEvent.class), - eventWith(request2, TransactionEndedEvent.class), - eventWith(NoOpSagaRequest.SAGA_END_REQUEST, SagaEndedEvent.class) - )); - } - - private Matcher eventWith( - SagaRequest sagaRequest, - Class type) { - - return new TypeSafeMatcher() { - @Override - protected boolean matchesSafely(SagaEvent event) { - SagaRequest request = event.payload(); - return sagaRequest.equals(request) - && event.getClass().equals(type); - } - - @Override - protected void describeMismatchSafely(SagaEvent item, Description mismatchDescription) { - SagaRequest request = item.payload(); - mismatchDescription.appendText( - "SagaEvent {" + request + "}"); - } - - @Override - public void describeTo(Description description) { - description.appendText( - "SagaEvent {" + sagaRequest + "}"); - } - }; - } - - private class EmbeddedPersistentStore extends EmbeddedEventStore implements PersistentStore { - - @Override - public Map> findPendingSagaEvents() { - return singletonMap(sagaId, singletonList( - new EventEnvelope(1L, new SagaStartedEvent(sagaId, sagaJson, NoOpSagaRequest.SAGA_START_REQUEST)))); - } - } - - protected abstract SagaFactory sagaFactory(PersistentStore eventStore); -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaIntegrationTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaIntegrationTest.java deleted file mode 100644 index d005ee7ff..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaIntegrationTest.java +++ /dev/null @@ -1,687 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static org.apache.servicecomb.saga.core.Compensation.SAGA_START_COMPENSATION; -import static org.apache.servicecomb.saga.core.Operation.TYPE_REST; -import static org.apache.servicecomb.saga.core.SagaEventMatcher.eventWith; -import static org.apache.servicecomb.saga.core.SagaResponse.EMPTY_RESPONSE; -import static org.apache.servicecomb.saga.core.SagaResponse.NONE_RESPONSE; -import static org.apache.servicecomb.saga.core.SagaTask.SAGA_END_TASK; -import static org.apache.servicecomb.saga.core.SagaTask.SAGA_REQUEST_TASK; -import static org.apache.servicecomb.saga.core.SagaTask.SAGA_START_TASK; -import static org.apache.servicecomb.saga.core.Transaction.SAGA_END_TRANSACTION; -import static org.apache.servicecomb.saga.core.Transaction.SAGA_START_TRANSACTION; -import static java.util.Arrays.asList; -import static java.util.Collections.emptySet; -import static java.util.Collections.singletonList; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.stubbing.Answer; - -import com.seanyinx.github.unit.scaffolding.Randomness; - -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import org.apache.servicecomb.saga.core.dag.Node; -import org.apache.servicecomb.saga.core.dag.SingleLeafDirectedAcyclicGraph; -import org.apache.servicecomb.saga.infrastructure.ContextAwareEventStore; -import org.apache.servicecomb.saga.infrastructure.EmbeddedEventStore; - -@SuppressWarnings("unchecked") -public class SagaIntegrationTest { - private static final String sagaId = Randomness.uniquify("sagaId"); - - private final FromJsonFormat> childrenExtractor = mock(FromJsonFormat.class); - private final SagaContext sagaContext = new SagaContextImpl(childrenExtractor); - private final IdGenerator idGenerator = new LongIdGenerator(); - private final EventStore eventStore = new EmbeddedEventStore(); - private final ContextAwareEventStore sagaLog = new ContextAwareEventStore(eventStore, sagaContext); - - private final Transaction transaction1 = mock(Transaction.class, "transaction1"); - private final Transaction transaction2 = mock(Transaction.class, "transaction2"); - private final Transaction transaction3 = mock(Transaction.class, "transaction3"); - private final Transaction transaction4 = mock(Transaction.class, "transaction4"); - - private final Compensation compensation1 = mock(Compensation.class, "compensation1"); - private final Compensation compensation2 = mock(Compensation.class, "compensation2"); - private final Compensation compensation3 = mock(Compensation.class, "compensation3"); - private final Compensation compensation4 = mock(Compensation.class, "compensation4"); - - private final Fallback fallback1 = mock(Fallback.class, "fallback1"); - - private final String requestJson = "{}"; - private final SagaRequest request1 = request("request1", "service1", transaction1, compensation1, fallback1); - private final SagaRequest request2 = request("request2", "service2", transaction2, compensation2, request1.id()); - private final SagaRequest request3 = request("request3", "service3", transaction3, compensation3, request1.id()); - private final SagaRequest request4 = request("request4", "service4", transaction4, compensation4, request3.id()); - - private final SagaResponse transactionResponse1 = new SuccessfulSagaResponse("transaction1"); - private final SagaResponse transactionResponse2 = new SuccessfulSagaResponse("transaction2"); - private final SagaResponse transactionResponse3 = new SuccessfulSagaResponse("transaction3"); - private final SagaResponse compensationResponse1 = new SuccessfulSagaResponse("compensation1"); - private final SagaResponse compensationResponse2 = new SuccessfulSagaResponse("compensation2"); - private final SagaResponse compensationResponse3 = new SuccessfulSagaResponse("compensation3"); - - @SuppressWarnings("ThrowableInstanceNeverThrown") - private final RuntimeException exception = new RuntimeException("oops"); - - private final Node node1 = new Node<>(1, request1); - private final Node node2 = new Node<>(2, request2); - private final Node node3 = new Node<>(3, request3); - private final Node node4 = new Node<>(4, request4); - private final Node root = new Node<>(0, NoOpSagaRequest.SAGA_START_REQUEST); - private final Node leaf = new Node<>(5, NoOpSagaRequest.SAGA_END_REQUEST); - private final SingleLeafDirectedAcyclicGraph sagaTaskGraph = new SingleLeafDirectedAcyclicGraph<>(root, leaf); - - private Saga saga; - private final Map tasks = new HashMap<>(); - - // root - node1 - node2 - leaf - @Before - public void setUp() throws Exception { - when(childrenExtractor.fromJson(anyString())).thenReturn(emptySet()); - when(childrenExtractor.fromJson(NONE_RESPONSE.body())).thenReturn(setOf("none")); - - when(transaction1.send(request1.serviceName(), EMPTY_RESPONSE)).thenReturn(transactionResponse1); - when(transaction2.send(request2.serviceName(), transactionResponse1)).thenReturn(transactionResponse2); - when(transaction3.send(request3.serviceName(), transactionResponse1)).thenReturn(transactionResponse3); - - when(compensation1.send(request1.serviceName(), compensationResponse2)).thenReturn(compensationResponse1); - when(compensation2.send(request2.serviceName(), compensationResponse3)).thenReturn(compensationResponse2); - when(compensation3.send(request3.serviceName(), EMPTY_RESPONSE)).thenReturn(compensationResponse3); - - root.addChild(node1); - node1.addChild(node2); - node2.addChild(leaf); - - SagaStartTask sagaStartTask = new SagaStartTask(sagaId, requestJson, sagaLog); - SagaEndTask sagaEndTask = new SagaEndTask(sagaId, sagaLog); - RequestProcessTask processTask = requestProcessTask(new BackwardRecovery()); - - tasks.put(SAGA_START_TASK, sagaStartTask); - tasks.put(SAGA_REQUEST_TASK, processTask); - tasks.put(SAGA_END_TASK, sagaEndTask); - - saga = new GraphBasedSaga(eventStore, tasks, sagaContext, sagaTaskGraph); - } - - @Test - public void transactionsAreRunSuccessfully() { - saga.run(); - - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionEndedEvent.class), - eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), EMPTY_RESPONSE); - verify(transaction2).send(request2.serviceName(), transactionResponse1); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - } - - // root - node1 - node2 - leaf - // \_ node3 _/ - @Test - public void compensateCommittedTransactionsOnFailure() { - addExtraChildToNode1(); - - // barrier to make sure the two transactions starts at the same time - CyclicBarrier barrier = new CyclicBarrier(2); - when(transaction2.send(request2.serviceName(), transactionResponse1)) - .thenAnswer( - withAnswer(() -> { - barrier.await(); - Thread.sleep(100); - throw exception; - })); - - when(transaction3.send(request3.serviceName(), transactionResponse1)) - .thenAnswer( - withAnswer(() -> { - barrier.await(); - return transactionResponse3; - })); - - saga.run(); - - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - anyOf(eventWith(sagaId, transaction2, TransactionStartedEvent.class), eventWith(sagaId, transaction3, TransactionStartedEvent.class)), - anyOf(eventWith(sagaId, transaction2, TransactionStartedEvent.class), eventWith(sagaId, transaction3, TransactionStartedEvent.class)), - eventWith(sagaId, transaction3, TransactionEndedEvent.class), - eventWith(sagaId, transaction2, TransactionAbortedEvent.class), - eventWith(sagaId, compensation3, TransactionCompensatedEvent.class), - eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - eventWith(sagaId, SAGA_START_COMPENSATION, SagaEndedEvent.class))); - - verify(transaction1).send(request1.serviceName(), EMPTY_RESPONSE); - verify(transaction2).send(request2.serviceName(), transactionResponse1); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3).send(request3.serviceName()); - } - - @Test - public void skipIgnoredTransaction() throws Exception { - addExtraChildToNode1(); - - when(childrenExtractor.fromJson(transactionResponse1.body())).thenReturn(setOf(request3.id())); - - saga.run(); - - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction3, TransactionStartedEvent.class), - eventWith(sagaId, transaction3, TransactionEndedEvent.class), - eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), EMPTY_RESPONSE); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void skipAllIgnoredTransactions() throws Exception { - node1.addChild(node3); - node3.addChild(node4); - node4.addChild(leaf); - - when(childrenExtractor.fromJson(transactionResponse1.body())).thenReturn(setOf("none")); - - saga.run(); - - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), EMPTY_RESPONSE); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction4, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - verify(compensation4, never()).send(request4.serviceName()); - } - - @Test - public void doNotCompensateIgnoredTransactions() throws Exception { - node1.addChild(node3); - node3.addChild(node4); - node4.addChild(leaf); - - when(childrenExtractor.fromJson(transactionResponse1.body())).thenReturn(setOf(request3.id())); - - when(transaction4.send(request4.serviceName(), transactionResponse3)).thenThrow(exception); - - saga.run(); - - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction3, TransactionStartedEvent.class), - eventWith(sagaId, transaction3, TransactionEndedEvent.class), - eventWith(sagaId, transaction4, TransactionStartedEvent.class), - eventWith(sagaId, transaction4, TransactionAbortedEvent.class), - eventWith(sagaId, transaction3, TransactionCompensatedEvent.class), - eventWith(sagaId, transaction1, TransactionCompensatedEvent.class), - eventWith(sagaId, SAGA_START_COMPENSATION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), EMPTY_RESPONSE); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - verify(transaction4).send(request4.serviceName(), transactionResponse3); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1).send(request1.serviceName()); - verify(compensation3).send(request3.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation4, never()).send(request4.serviceName()); - } - - // root - node1 - node2 - leaf - // \_ node3 _/ - @Test - public void redoHangingTransactionsOnFailure() throws InterruptedException { - addExtraChildToNode1(); - - // barrier to make sure the two transactions starts at the same time - CyclicBarrier barrier = new CyclicBarrier(2); - when(transaction3.send(request3.serviceName(), transactionResponse1)) - .thenAnswer(withAnswer(() -> { - barrier.await(); - throw exception; - })); - - CountDownLatch latch = new CountDownLatch(1); - - when(transaction2.send(request2.serviceName(), transactionResponse1)) - .thenAnswer(withAnswer(() -> { - barrier.await(); - latch.await(); - return transactionResponse2; - })).thenReturn(transactionResponse2); - - saga.run(); - - // the ordering of events may not be consistence due to concurrent processing of requests - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - anyOf( - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction3, TransactionStartedEvent.class)), - anyOf( - eventWith(sagaId, transaction3, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class)), - eventWith(sagaId, transaction3, TransactionAbortedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionEndedEvent.class), - eventWith(sagaId, compensation2, TransactionCompensatedEvent.class), - eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - eventWith(sagaId, SAGA_START_COMPENSATION, SagaEndedEvent.class))); - - verify(transaction1).send(request1.serviceName(), EMPTY_RESPONSE); - verify(transaction2, times(2)).send(request2.serviceName(), transactionResponse1); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - - latch.countDown(); - } - - @Test - public void retriesFailedTransactionTillSuccess() { - RequestProcessTask processTask = requestProcessTask(new ForwardRecovery()); - tasks.put(SAGA_REQUEST_TASK, processTask); - - when(transaction2.send(request2.serviceName(), transactionResponse1)) - .thenThrow(exception).thenThrow(exception).thenReturn(transactionResponse2); - - saga.run(); - - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionEndedEvent.class), - eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), EMPTY_RESPONSE); - verify(transaction2, times(3)).send(request2.serviceName(), transactionResponse1); - - verify(compensation1, never()).send(anyString(), any(SagaResponse.class)); - verify(compensation2, never()).send(anyString(), any(SagaResponse.class)); - } - - @Test - public void fallbackWhenCompensationFailed() { - int retries = 3; - - when(transaction2.send(request2.serviceName(), transactionResponse1)).thenThrow(exception); - when(compensation1.send(request1.serviceName())).thenThrow(exception); - when(compensation1.retries()).thenReturn(retries); - - saga.run(); - - verify(transaction1).send(request1.serviceName(), EMPTY_RESPONSE); - verify(transaction2).send(request2.serviceName(), transactionResponse1); - - verify(compensation1, times(retries + 1)).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - - verify(fallback1).send(request1.serviceName()); - } - - @Test - public void restoresSagaToTransactionStateByPlayingAllEvents() { - addExtraChildToNode1(); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1, transactionResponse1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2, transactionResponse2)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionEndedEvent.class), - eventWith(sagaId, transaction3, TransactionStartedEvent.class), - eventWith(sagaId, transaction3, TransactionEndedEvent.class), - eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void restoresPartialTransactionByPlayingAllEvents() { - addExtraChildToNode1(); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1, transactionResponse1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2, transactionResponse2)), - envelope(new TransactionStartedEvent(sagaId, request3)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionEndedEvent.class), - eventWith(sagaId, transaction3, TransactionStartedEvent.class), - eventWith(sagaId, transaction3, TransactionStartedEvent.class), - eventWith(sagaId, transaction3, TransactionEndedEvent.class), - eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void restoresToCompensationFromAbortedTransactionByPlayingAllEvents() { - addExtraChildToNode1(); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2)), - envelope(new TransactionStartedEvent(sagaId, request3)), - envelope(new TransactionAbortedEvent(sagaId, request3, exception)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionEndedEvent.class), - eventWith(sagaId, transaction3, TransactionStartedEvent.class), - eventWith(sagaId, transaction3, TransactionAbortedEvent.class), - eventWith(sagaId, compensation2, TransactionCompensatedEvent.class), - eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - eventWith(sagaId, SAGA_START_COMPENSATION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void restoresSagaToCompensationStateByPlayingAllEvents() { - addExtraChildToNode1(); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2)), - envelope(new TransactionStartedEvent(sagaId, request3)), - envelope(new TransactionEndedEvent(sagaId, request3)), - envelope(new TransactionCompensatedEvent(sagaId, request2)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionEndedEvent.class), - eventWith(sagaId, transaction3, TransactionStartedEvent.class), - eventWith(sagaId, transaction3, TransactionEndedEvent.class), - eventWith(sagaId, compensation2, TransactionCompensatedEvent.class), - eventWith(sagaId, compensation3, TransactionCompensatedEvent.class), - eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - eventWith(sagaId, SAGA_START_COMPENSATION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3).send(request3.serviceName()); - } - - @Test - public void restoresPartialCompensationByPlayingAllEvents() { - addExtraChildToNode1(); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2)), - envelope(new TransactionStartedEvent(sagaId, request3)), - envelope(new TransactionAbortedEvent(sagaId, request3, exception)), - envelope(new TransactionCompensatedEvent(sagaId, request2)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionEndedEvent.class), - eventWith(sagaId, transaction3, TransactionStartedEvent.class), - eventWith(sagaId, transaction3, TransactionAbortedEvent.class), - eventWith(sagaId, compensation2, TransactionCompensatedEvent.class), - eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - eventWith(sagaId, SAGA_START_COMPENSATION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void restoresSagaToEndStateByPlayingAllEvents() { - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, contains( - eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - eventWith(sagaId, transaction1, TransactionStartedEvent.class), - eventWith(sagaId, transaction1, TransactionEndedEvent.class), - eventWith(sagaId, transaction2, TransactionStartedEvent.class), - eventWith(sagaId, transaction2, TransactionEndedEvent.class), - eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - } - - @Test - public void failFastIfSagaLogIsDown() throws Exception { - SagaLog sagaLog = mock(SagaLog.class); - tasks.put(SAGA_START_TASK, new SagaStartTask(sagaId, requestJson, sagaLog)); - - doThrow(RuntimeException.class).when(sagaLog).offer(any(SagaStartedEvent.class)); - - try { - saga.run(); - expectFailing(SagaStartFailedException.class); - } catch (SagaStartFailedException e) { - assertThat(e.getMessage(), is("Failed to persist SagaStartedEvent for " + requestJson)); - } - - verify(sagaLog).offer(any(SagaStartedEvent.class)); - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - } - - private Answer withAnswer(Callable callable) { - return invocationOnMock -> callable.call(); - } - - private EventEnvelope envelope(SagaEvent event) { - return new EventEnvelope(idGenerator.nextId(), event); - } - - private void addExtraChildToNode1() { - node1.addChild(node3); - node3.addChild(leaf); - } - - private SagaRequest request(String requestId, - String serviceName, - Transaction transaction, - Compensation compensation, - String... parentIds) { - - return new SagaRequestImpl(requestId, serviceName, TYPE_REST, transaction, compensation, parentIds); - } - - private SagaRequest request(String requestId, - String serviceName, - Transaction transaction, - Compensation compensation, - Fallback fallback) { - - return new SagaRequestImpl(requestId, serviceName, TYPE_REST, transaction, compensation, fallback); - } - - private HashSet setOf(String requestId) { - return new HashSet<>(singletonList(requestId)); - } - - private RequestProcessTask requestProcessTask(RecoveryPolicy recoveryPolicy) { - return new RequestProcessTask(sagaId, sagaLog, recoveryPolicy, new FallbackPolicy(100)); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaStartTaskTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaStartTaskTest.java deleted file mode 100644 index b1d0c4e45..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/SagaStartTaskTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.startsWith; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -public class SagaStartTaskTest { - private final SagaRequest request = mock(SagaRequest.class); - private final SagaLog sagaLog = mock(SagaLog.class); - - private final String sagaId = "0"; - private final String requestJson = null; - private final SagaStartTask sagaStartTask = new SagaStartTask(sagaId, requestJson, sagaLog); - - @Test - public void emptyResponseOnSuccessfulEventPersistence() throws Exception { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SagaStartedEvent.class); - doNothing().when(sagaLog).offer(argumentCaptor.capture()); - - sagaStartTask.commit(request, SagaResponse.EMPTY_RESPONSE); - - SagaStartedEvent event = argumentCaptor.getValue(); - assertThat(event.sagaId, is(sagaId)); - assertThat(event.json(null), is(requestJson)); - assertThat(event.payload(), is(request)); - } - - @Test - public void blowsUpWhenEventIsNotPersisted() { - doThrow(RuntimeException.class).when(sagaLog).offer(any(SagaStartedEvent.class)); - - try { - sagaStartTask.commit(request, SagaResponse.EMPTY_RESPONSE); - expectFailing(SagaStartFailedException.class); - } catch (SagaStartFailedException e) { - assertThat(e.getMessage(), startsWith("Failed to persist SagaStartedEvent")); - } - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/TransactionImpl.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/TransactionImpl.java deleted file mode 100644 index a59b14210..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/TransactionImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import java.util.Map; - -public class TransactionImpl extends RestOperation implements Transaction { - - public TransactionImpl(String path, String method, Map> params) { - super(path, method, params); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaExecutionComponentTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaExecutionComponentTest.java deleted file mode 100644 index 01f8adbf4..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaExecutionComponentTest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import org.apache.servicecomb.saga.core.application.SagaFactory; -import org.apache.servicecomb.saga.core.PersistentStore; -import org.apache.servicecomb.saga.core.SagaExecutionComponentTestBase; - - -public class ActorBasedSagaExecutionComponentTest extends SagaExecutionComponentTestBase { - - @Override - protected SagaFactory sagaFactory(PersistentStore eventStore) { - return new ActorBasedSagaFactory(500, eventStore, null); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaIntegrationTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaIntegrationTest.java deleted file mode 100644 index ac649f067..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/ActorBasedSagaIntegrationTest.java +++ /dev/null @@ -1,691 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import static org.apache.servicecomb.saga.core.Transaction.SAGA_END_TRANSACTION; -import static org.apache.servicecomb.saga.core.Transaction.SAGA_START_TRANSACTION; -import static java.util.Arrays.asList; -import static java.util.Collections.emptySet; -import static java.util.Collections.singletonList; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; - -import org.apache.servicecomb.saga.core.Compensation; -import org.apache.servicecomb.saga.core.EventEnvelope; -import org.apache.servicecomb.saga.core.EventStore; -import org.apache.servicecomb.saga.core.Fallback; -import org.apache.servicecomb.saga.core.ForwardRecovery; -import org.apache.servicecomb.saga.core.IdGenerator; -import org.apache.servicecomb.saga.core.LongIdGenerator; -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.Operation; -import org.apache.servicecomb.saga.core.Saga; -import org.apache.servicecomb.saga.core.SagaEventMatcher; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaRequestImpl; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.SagaStartedEvent; -import org.apache.servicecomb.saga.core.SuccessfulSagaResponse; -import org.apache.servicecomb.saga.core.TransactionCompensatedEvent; -import org.apache.servicecomb.saga.core.TransactionStartedEvent; -import org.apache.servicecomb.saga.core.application.SagaFactory; -import org.hamcrest.CoreMatchers; -import org.hamcrest.collection.IsIterableContainingInOrder; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.stubbing.Answer; - -import com.seanyinx.github.unit.scaffolding.Randomness; - -import org.apache.servicecomb.saga.core.BackwardRecovery; -import org.apache.servicecomb.saga.core.PersistentStore; -import org.apache.servicecomb.saga.core.SagaDefinition; -import org.apache.servicecomb.saga.core.SagaEndedEvent; -import org.apache.servicecomb.saga.core.SagaEvent; -import org.apache.servicecomb.saga.core.Transaction; -import org.apache.servicecomb.saga.core.TransactionAbortedEvent; -import org.apache.servicecomb.saga.core.TransactionEndedEvent; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import org.apache.servicecomb.saga.infrastructure.EmbeddedEventStore; - -@SuppressWarnings("unchecked") -public class ActorBasedSagaIntegrationTest { - private static final String sagaId = Randomness.uniquify("sagaId"); - - private final FromJsonFormat> childrenExtractor = mock(FromJsonFormat.class); - private final IdGenerator idGenerator = new LongIdGenerator(); - private final EventStore eventStore = new EmbeddedEventStore(); - - private final PersistentStore persistentStore = mock(PersistentStore.class); - private final SagaDefinition sagaDefinition = mock(SagaDefinition.class); - - private final Transaction transaction1 = mock(Transaction.class, "transaction1"); - private final Transaction transaction2 = mock(Transaction.class, "transaction2"); - private final Transaction transaction3 = mock(Transaction.class, "transaction3"); - private final Transaction transaction4 = mock(Transaction.class, "transaction4"); - - private final Compensation compensation1 = mock(Compensation.class, "compensation1"); - private final Compensation compensation2 = mock(Compensation.class, "compensation2"); - private final Compensation compensation3 = mock(Compensation.class, "compensation3"); - private final Compensation compensation4 = mock(Compensation.class, "compensation4"); - - private final Fallback fallback1 = mock(Fallback.class, "fallback1"); - - private final String requestJson = "{}"; - private final SagaRequest request1 = request("request1", "service1", transaction1, compensation1, fallback1); - private final SagaRequest request2 = request("request2", "service2", transaction2, compensation2, request1.id()); - private final SagaRequest request3 = request("request3", "service3", transaction3, compensation3, request1.id()); - private final SagaRequest request4 = request("request4", "service4", transaction4, compensation4, request3.id()); - - private final SagaResponse transactionResponse1 = new SuccessfulSagaResponse("transaction1"); - private final SagaResponse transactionResponse2 = new SuccessfulSagaResponse("transaction2"); - private final SagaResponse transactionResponse3 = new SuccessfulSagaResponse("transaction3"); - private final SagaResponse compensationResponse1 = new SuccessfulSagaResponse("compensation1"); - private final SagaResponse compensationResponse2 = new SuccessfulSagaResponse("compensation2"); - private final SagaResponse compensationResponse3 = new SuccessfulSagaResponse("compensation3"); - - @SuppressWarnings("ThrowableInstanceNeverThrown") - private final RuntimeException exception = new RuntimeException("oops"); - - private Saga saga; - private final SagaFactory sagaFactory = new ActorBasedSagaFactory(100, persistentStore, childrenExtractor); - - // root - node1 - node2 - leaf - @Before - public void setUp() throws Exception { - when(sagaDefinition.policy()).thenReturn(new BackwardRecovery()); - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2}); - - when(childrenExtractor.fromJson(anyString())).thenReturn(emptySet()); - when(childrenExtractor.fromJson(SagaResponse.NONE_RESPONSE.body())).thenReturn(setOf("none")); - - when(transaction1.send(request1.serviceName(), SagaResponse.EMPTY_RESPONSE)).thenReturn(transactionResponse1); - when(transaction2.send(request2.serviceName(), transactionResponse1)).thenReturn(transactionResponse2); - when(transaction3.send(request3.serviceName(), transactionResponse1)).thenReturn(transactionResponse3); - - when(compensation1.send(request1.serviceName(), compensationResponse2)).thenReturn(compensationResponse1); - when(compensation2.send(request2.serviceName(), compensationResponse3)).thenReturn(compensationResponse2); - when(compensation3.send(request3.serviceName(), SagaResponse.EMPTY_RESPONSE)).thenReturn(compensationResponse3); - } - - @After - public void tearDown() throws Exception { - sagaFactory.terminate(); - assertTrue(sagaFactory.isTerminated()); - } - - @Test - public void transactionsAreRunSuccessfully() { - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - saga.run(); - - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), SagaResponse.EMPTY_RESPONSE); - verify(transaction2).send(request2.serviceName(), transactionResponse1); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - } - - // root - node1 - node2 - leaf - // \_ node3 _/ - @Test - public void compensateCommittedTransactionsOnFailure() { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - // barrier to make sure the two transactions starts at the same time - CyclicBarrier barrier = new CyclicBarrier(2); - when(transaction2.send(request2.serviceName(), transactionResponse1)) - .thenAnswer( - withAnswer(() -> { - barrier.await(); - Thread.sleep(100); - throw exception; - })); - - when(transaction3.send(request3.serviceName(), transactionResponse1)) - .thenAnswer( - withAnswer(() -> { - barrier.await(); - return transactionResponse3; - })); - - saga.run(); - - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - CoreMatchers.anyOf(SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), SagaEventMatcher - .eventWith(sagaId, transaction3, TransactionStartedEvent.class)), - CoreMatchers.anyOf(SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), SagaEventMatcher - .eventWith(sagaId, transaction3, TransactionStartedEvent.class)), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionAbortedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation3, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, Compensation.SAGA_START_COMPENSATION, SagaEndedEvent.class))); - - verify(transaction1).send(request1.serviceName(), SagaResponse.EMPTY_RESPONSE); - verify(transaction2).send(request2.serviceName(), transactionResponse1); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3).send(request3.serviceName()); - } - - @Test - public void skipIgnoredTransaction() throws Exception { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - when(childrenExtractor.fromJson(transactionResponse1.body())).thenReturn(setOf(request3.id())); - - saga.run(); - - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), SagaResponse.EMPTY_RESPONSE); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void skipAllIgnoredTransactions() throws Exception { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3, request4}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - when(childrenExtractor.fromJson(transactionResponse1.body())).thenReturn(setOf("none")); - - saga.run(); - - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), SagaResponse.EMPTY_RESPONSE); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction4, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - verify(compensation4, never()).send(request4.serviceName()); - } - - @Test - public void doNotCompensateIgnoredTransactions() throws Exception { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3, request4}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - when(childrenExtractor.fromJson(transactionResponse1.body())).thenReturn(setOf(request3.id())); - - when(transaction4.send(request4.serviceName(), transactionResponse3)).thenThrow(exception); - - saga.run(); - - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction4, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction4, TransactionAbortedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, Compensation.SAGA_START_COMPENSATION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), SagaResponse.EMPTY_RESPONSE); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - verify(transaction4).send(request4.serviceName(), transactionResponse3); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1).send(request1.serviceName()); - verify(compensation3).send(request3.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation4, never()).send(request4.serviceName()); - } - - // TODO: 2017/10/31 actor will hang and its parent and children will be blocked without its response, timeout must be applied - @Ignore - // root - node1 - node2 - leaf - // \_ node3 _/ - @Test - public void redoHangingTransactionsOnFailure() throws InterruptedException { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - // barrier to make sure the two transactions starts at the same time - CyclicBarrier barrier = new CyclicBarrier(2); - when(transaction3.send(request3.serviceName(), transactionResponse1)) - .thenAnswer(withAnswer(() -> { - barrier.await(); - throw exception; - })); - - CountDownLatch latch = new CountDownLatch(1); - - when(transaction2.send(request2.serviceName(), transactionResponse1)) - .thenAnswer(withAnswer(() -> { - barrier.await(); - latch.await(1, SECONDS); - return transactionResponse2; - })).thenReturn(transactionResponse2); - - saga.run(); - - // the ordering of events may not be consistence due to concurrent processing of requests - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - CoreMatchers.anyOf( - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class)), - CoreMatchers.anyOf( - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class)), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionAbortedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation2, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, Compensation.SAGA_START_COMPENSATION, SagaEndedEvent.class))); - - verify(transaction1).send(request1.serviceName(), SagaResponse.EMPTY_RESPONSE); - verify(transaction2, times(2)).send(request2.serviceName(), transactionResponse1); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - - latch.countDown(); - } - - @Test - public void retriesFailedTransactionTillSuccess() { - when(sagaDefinition.policy()).thenReturn(new ForwardRecovery()); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - when(transaction2.send(request2.serviceName(), transactionResponse1)) - .thenThrow(exception).thenThrow(exception).thenReturn(transactionResponse2); - - saga.run(); - - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1).send(request1.serviceName(), SagaResponse.EMPTY_RESPONSE); - verify(transaction2, times(3)).send(request2.serviceName(), transactionResponse1); - - verify(compensation1, never()).send(anyString(), any(SagaResponse.class)); - verify(compensation2, never()).send(anyString(), any(SagaResponse.class)); - } - - @Test - public void fallbackWhenCompensationFailed() { - int retries = 3; - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - when(transaction2.send(request2.serviceName(), transactionResponse1)).thenThrow(exception); - when(compensation1.send(request1.serviceName())).thenThrow(exception); - when(compensation1.retries()).thenReturn(retries); - - saga.run(); - - verify(transaction1).send(request1.serviceName(), SagaResponse.EMPTY_RESPONSE); - verify(transaction2).send(request2.serviceName(), transactionResponse1); - - verify(compensation1, times(retries + 1)).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - - verify(fallback1).send(request1.serviceName()); - } - - @Test - public void restoresSagaToTransactionStateByPlayingAllEvents() { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1, transactionResponse1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2, transactionResponse2)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void restoresPartialTransactionByPlayingAllEvents() { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1, transactionResponse1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2, transactionResponse2)), - envelope(new TransactionStartedEvent(sagaId, request3)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3).send(request3.serviceName(), transactionResponse1); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void restoresToCompensationFromAbortedTransactionByPlayingAllEvents() { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2)), - envelope(new TransactionStartedEvent(sagaId, request3)), - envelope(new TransactionAbortedEvent(sagaId, request3, exception)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionAbortedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation2, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, Compensation.SAGA_START_COMPENSATION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void restoresSagaToCompensationStateByPlayingAllEvents() { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2)), - envelope(new TransactionStartedEvent(sagaId, request3)), - envelope(new TransactionAbortedEvent(sagaId, request3, exception)), - envelope(new TransactionCompensatedEvent(sagaId, request2)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionAbortedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation2, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, Compensation.SAGA_START_COMPENSATION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void restoresPartialCompensationByPlayingAllEvents() { - when(sagaDefinition.requests()).thenReturn(new SagaRequest[]{request1, request2, request3}); - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2)), - envelope(new TransactionStartedEvent(sagaId, request3)), - envelope(new TransactionAbortedEvent(sagaId, request3, exception)), - envelope(new TransactionCompensatedEvent(sagaId, request2)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction3, TransactionAbortedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation2, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, compensation1, TransactionCompensatedEvent.class), - SagaEventMatcher.eventWith(sagaId, Compensation.SAGA_START_COMPENSATION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction3, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - verify(compensation3, never()).send(request3.serviceName()); - } - - @Test - public void restoresSagaToEndStateByPlayingAllEvents() { - saga = sagaFactory.createSaga(requestJson, sagaId, eventStore, sagaDefinition); - Iterable events = asList( - envelope(new SagaStartedEvent(sagaId, requestJson, NoOpSagaRequest.SAGA_START_REQUEST)), - envelope(new TransactionStartedEvent(sagaId, request1)), - envelope(new TransactionEndedEvent(sagaId, request1)), - envelope(new TransactionStartedEvent(sagaId, request2)), - envelope(new TransactionEndedEvent(sagaId, request2)) - ); - - eventStore.populate(events); - saga.play(); - - saga.run(); - assertThat(eventStore, IsIterableContainingInOrder.contains( - SagaEventMatcher.eventWith(sagaId, SAGA_START_TRANSACTION, SagaStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction1, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionStartedEvent.class), - SagaEventMatcher.eventWith(sagaId, transaction2, TransactionEndedEvent.class), - SagaEventMatcher.eventWith(sagaId, SAGA_END_TRANSACTION, SagaEndedEvent.class) - )); - - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - } - - @Test - public void failFastIfSagaLogIsDown() throws Exception { - EventStore sagaLog = mock(EventStore.class); - saga = sagaFactory.createSaga(requestJson, sagaId, sagaLog, sagaDefinition); - - doThrow(RuntimeException.class).when(sagaLog).offer(any(SagaStartedEvent.class)); - - saga.run(); - - verify(sagaLog).offer(any(SagaStartedEvent.class)); - verify(transaction1, never()).send(anyString(), any(SagaResponse.class)); - verify(transaction2, never()).send(anyString(), any(SagaResponse.class)); - - verify(compensation1, never()).send(request1.serviceName()); - verify(compensation2, never()).send(request2.serviceName()); - } - - private Answer withAnswer(Callable callable) { - return invocationOnMock -> callable.call(); - } - - private EventEnvelope envelope(SagaEvent event) { - return new EventEnvelope(idGenerator.nextId(), event); - } - - private SagaRequest request(String requestId, - String serviceName, - Transaction transaction, - Compensation compensation, - String... parentIds) { - - return new SagaRequestImpl(requestId, serviceName, Operation.TYPE_REST, transaction, compensation, parentIds); - } - - private SagaRequest request(String requestId, - String serviceName, - Transaction transaction, - Compensation compensation, - Fallback fallback) { - - return new SagaRequestImpl(requestId, serviceName, Operation.TYPE_REST, transaction, compensation, fallback); - } - - private HashSet setOf(String requestId) { - return new HashSet<>(singletonList(requestId)); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/CompletionCallbackActorTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/CompletionCallbackActorTest.java deleted file mode 100644 index 5823a069f..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/CompletionCallbackActorTest.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import static akka.actor.ActorRef.noSender; -import static akka.actor.Props.empty; -import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; -import static org.awaitility.Awaitility.await; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertThat; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.actors.messages.AbortMessage; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import org.apache.servicecomb.saga.core.FailedSagaResponse; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.actors.messages.CompensateMessage; -import org.apache.servicecomb.saga.core.actors.messages.FailMessage; -import org.apache.servicecomb.saga.core.actors.messages.TransactMessage; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.testkit.javadsl.TestKit; - -public class CompletionCallbackActorTest { - private static final ActorSystem actorSystem = ActorSystem.create(); - - private final SagaResponse response = Mockito.mock(SagaResponse.class); - private final RequestActorContext context = new RequestActorContext(null); - - private final ActorRef actor1 = someActor(); - private final ActorRef actor2 = someActor(); - - @Before - public void setUp() throws Exception { - context.addActor(uniquify("requestId"), actor1); - context.addActor(uniquify("requestId"), actor2); - } - - @AfterClass - public static void tearDown() throws Exception { - TestKit.shutdownActorSystem(actorSystem); - } - - @Test - public void killAllOnTransactionComplete() throws Exception { - new TestKit(actorSystem) {{ - CompletableFuture future = new CompletableFuture<>(); - - ActorRef actor = actorSystem.actorOf(CompletionCallbackActor.props(future)); - - actor.tell(context, noSender()); - actor.tell(new TransactMessage(null, response), noSender()); - - await().atMost(2, TimeUnit.SECONDS) - .until(() -> actor1.isTerminated() && actor2.isTerminated() && actor.isTerminated()); - - assertThat(future.get(), is(response)); - }}; - } - - @Test - public void killAllOnCompensationComplete() throws Exception { - new TestKit(actorSystem) {{ - CompletableFuture future = new CompletableFuture<>(); - - ActorRef actor = actorSystem.actorOf(CompletionCallbackActor.props(future)); - - actor.tell(context, noSender()); - actor.tell(new CompensateMessage(response), noSender()); - - await().atMost(2, TimeUnit.SECONDS) - .until(() -> actor1.isTerminated() && actor2.isTerminated() && actor.isTerminated()); - - assertThat(future.get(), is(response)); - }}; - } - - @Test - public void killAllOnFailure() throws Exception { - new TestKit(actorSystem) {{ - CompletableFuture future = new CompletableFuture<>(); - - ActorRef actor = actorSystem.actorOf(CompletionCallbackActor.props(future)); - - actor.tell(context, noSender()); - actor.tell(new FailMessage(new RuntimeException("oops")), noSender()); - - await().atMost(2, TimeUnit.SECONDS) - .until(() -> actor1.isTerminated() && actor2.isTerminated() && actor.isTerminated()); - - assertThat(future.get(), is(instanceOf(FailedSagaResponse.class))); - }}; - } - - @Test - public void tellLeafToCompensateOnAbort() throws Exception { - new TestKit(actorSystem) {{ - context.addActor(NoOpSagaRequest.SAGA_END_REQUEST.id(), getRef()); - CompletableFuture future = new CompletableFuture<>(); - - ActorRef actor = actorSystem.actorOf(CompletionCallbackActor.props(future)); - - actor.tell(context, noSender()); - AbortMessage message = new AbortMessage(new RuntimeException("oops")); - actor.tell(message, noSender()); - - CompensateMessage compensateMessage = (CompensateMessage) receiveOne(duration("2 seconds")); - assertThat(compensateMessage.response(), is(message.response())); - }}; - } - - private ActorRef someActor() { - return actorSystem.actorOf(empty()); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/EventContextImplTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/EventContextImplTest.java deleted file mode 100644 index cfd378876..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/EventContextImplTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; - -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.actors.messages.AbortRecoveryMessage; -import org.apache.servicecomb.saga.core.actors.messages.CompensationRecoveryMessage; -import org.apache.servicecomb.saga.core.actors.messages.TransactionRecoveryMessage; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.scalatest.junit.JUnitSuite; - -import akka.actor.ActorSystem; -import akka.testkit.javadsl.TestKit; - -public class EventContextImplTest extends JUnitSuite { - private static final ActorSystem actorSystem = ActorSystem.create(); - - private final SagaRequest request = Mockito.mock(SagaRequest.class); - private final SagaResponse response = Mockito.mock(SagaResponse.class); - - private final RequestActorContext context = new RequestActorContext(null); - private final EventContextImpl eventContext = new EventContextImpl(context); - private final String requestId = uniquify("requestId"); - - @Before - public void setUp() throws Exception { - when(request.id()).thenReturn(requestId); - } - - @AfterClass - public static void tearDown() throws Exception { - TestKit.shutdownActorSystem(actorSystem); - } - - @Test - public void sendTransactionRecoveryMessageToActor_OnTransactionEnd() throws Exception { - new TestKit(actorSystem) {{ - context.addActor(requestId, getRef()); - - eventContext.endTransaction(request, response); - - TransactionRecoveryMessage message = (TransactionRecoveryMessage) receiveOne(duration("2 seconds")); - assertThat(message.response(), is(response)); - }}; - } - - @Test - public void sendCompensationRecoveryMessageToActor_OnCompensationEnd() throws Exception { - new TestKit(actorSystem) {{ - context.addActor(requestId, getRef()); - - eventContext.compensateTransaction(request, response); - - expectMsgClass(CompensationRecoveryMessage.class); - }}; - } - - @Test - public void sendAbortMessageToActor_OnAbort() throws Exception { - new TestKit(actorSystem) {{ - context.addActor(requestId, getRef()); - - eventContext.abortTransaction(request, response); - - AbortRecoveryMessage message = ((AbortRecoveryMessage) receiveOne(duration("2 seconds"))); - assertThat(message.response(), is(response)); - }}; - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/RequestActorBuilderTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/RequestActorBuilderTest.java deleted file mode 100644 index b3a2c149e..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/RequestActorBuilderTest.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.SagaTask; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.scalatest.junit.JUnitSuite; - -import com.seanyinx.github.unit.scaffolding.Randomness; - -import org.apache.servicecomb.saga.core.CompositeSagaResponse; -import org.apache.servicecomb.saga.core.actors.messages.CompensateMessage; -import org.apache.servicecomb.saga.core.actors.messages.TransactMessage; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.testkit.javadsl.TestKit; - -@SuppressWarnings("unchecked") -public class RequestActorBuilderTest extends JUnitSuite { - private static final ActorSystem actorSystem = ActorSystem.create(); - - private final String requestId1 = Randomness.uniquify("requestId1"); - private final String requestId2 = Randomness.uniquify("requestId2"); - private final String requestId3 = Randomness.uniquify("requestId3"); - private final String taskId = "some task"; - - private final SagaRequest request1 = Mockito.mock(SagaRequest.class); - private final SagaRequest request2 = Mockito.mock(SagaRequest.class); - private final SagaRequest request3 = Mockito.mock(SagaRequest.class); - - private final SagaResponse response1 = Mockito.mock(SagaResponse.class); - private final SagaResponse response2 = Mockito.mock(SagaResponse.class); - private final SagaResponse response3 = Mockito.mock(SagaResponse.class); - - private final SagaRequest[] requests = {request1, request2, request3}; - - private final SagaTask task = Mockito.mock(SagaTask.class); - private final Map tasks = new HashMap<>(); - - private final FromJsonFormat> childrenExtractor = Mockito.mock(FromJsonFormat.class); - private final RequestActorBuilder actorBuilder = new RequestActorBuilder(actorSystem, childrenExtractor); - - @Before - public void setUp() throws Exception { - tasks.put(SagaTask.SAGA_START_TASK, task); - tasks.put(SagaTask.SAGA_END_TASK, task); - tasks.put(taskId, task); - - when(request1.id()).thenReturn(requestId1); - when(request2.id()).thenReturn(requestId2); - when(request3.id()).thenReturn(requestId3); - - when(request1.task()).thenReturn(taskId); - when(request2.task()).thenReturn(taskId); - when(request3.task()).thenReturn(taskId); - - when(request1.parents()).thenReturn(new String[0]); - when(request2.parents()).thenReturn(new String[] {requestId1}); - when(request3.parents()).thenReturn(new String[] {requestId1}); - - when(task.commit(NoOpSagaRequest.SAGA_START_REQUEST, SagaResponse.EMPTY_RESPONSE)).thenReturn( - SagaResponse.EMPTY_RESPONSE); - when(task.commit(request1, SagaResponse.EMPTY_RESPONSE)).thenReturn(response1); - when(task.commit(request2, response1)).thenReturn(response2); - when(task.commit(request3, response1)).thenReturn(response3); - - when(childrenExtractor.fromJson(anyString())).thenReturn(Collections.emptySet()); - } - - @AfterClass - public static void tearDown() throws Exception { - TestKit.shutdownActorSystem(actorSystem); - } - - @Test - public void createOneActorPerRequest() throws Exception { - new TestKit(actorSystem) {{ - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SagaResponse.class); - when(task.commit(eq(NoOpSagaRequest.SAGA_END_REQUEST), argumentCaptor.capture())).thenReturn( - SagaResponse.EMPTY_RESPONSE); - - ActorRef root = actorBuilder.build(requests, tasks, getRef()).actorOf(NoOpSagaRequest.SAGA_START_REQUEST.id()); - - root.tell(new TransactMessage(NoOpSagaRequest.SAGA_START_REQUEST, SagaResponse.EMPTY_RESPONSE), getRef()); - - List responses = receiveN(1, duration("2 seconds")).stream() - .map(o -> ((TransactMessage) o).response()) - .collect(Collectors.toList()); - - assertThat(responses, Matchers.containsInAnyOrder(SagaResponse.EMPTY_RESPONSE)); - - verify(task).commit(NoOpSagaRequest.SAGA_START_REQUEST, SagaResponse.EMPTY_RESPONSE); - verify(task).commit(request1, SagaResponse.EMPTY_RESPONSE); - verify(task).commit(request2, response1); - verify(task).commit(request3, response1); - verify(task).commit(eq(NoOpSagaRequest.SAGA_END_REQUEST), any(SagaResponse.class)); - - SagaResponse response = argumentCaptor.getValue(); - assertThat(response, instanceOf(CompositeSagaResponse.class)); - assertThat(((CompositeSagaResponse) response).responses(), - containsInAnyOrder(response2, response3)); - }}; - } - - @Test - public void compensateAllCompletedTransactions() throws Exception { - new TestKit(actorSystem) {{ - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SagaResponse.class); - when(task.commit(eq(NoOpSagaRequest.SAGA_END_REQUEST), argumentCaptor.capture())).thenReturn( - SagaResponse.EMPTY_RESPONSE); - - ActorRef root = actorBuilder.build(requests, tasks, getRef()).actorOf(NoOpSagaRequest.SAGA_START_REQUEST.id()); - - root.tell(new TransactMessage(NoOpSagaRequest.SAGA_START_REQUEST, SagaResponse.EMPTY_RESPONSE), getRef()); - - List responses = receiveN(1, duration("2 seconds")).stream() - .map(o -> ((TransactMessage) o).response()) - .collect(Collectors.toList()); - - assertThat(responses, Matchers.containsInAnyOrder(SagaResponse.EMPTY_RESPONSE)); - - CompensateMessage message = new CompensateMessage(response1); - getLastSender().tell(message, getRef()); - expectMsg(message); - - verify(task).compensate(NoOpSagaRequest.SAGA_START_REQUEST); - verify(task).compensate(request1); - verify(task).compensate(request2); - verify(task).compensate(request3); - verify(task).compensate(NoOpSagaRequest.SAGA_END_REQUEST); - }}; - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/RequestActorTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/RequestActorTest.java deleted file mode 100644 index 776b5aad1..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/actors/RequestActorTest.java +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.actors; - -import static akka.actor.ActorRef.noSender; -import static akka.actor.Props.empty; -import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; -import static java.util.Collections.emptySet; -import static java.util.Collections.singleton; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.servicecomb.saga.core.CompositeSagaResponse; -import org.apache.servicecomb.saga.core.FailedSagaResponse; -import org.apache.servicecomb.saga.core.Operation; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.SagaStartFailedException; -import org.apache.servicecomb.saga.core.SagaTask; -import org.apache.servicecomb.saga.core.TransactionFailedException; -import org.apache.servicecomb.saga.core.actors.messages.AbortMessage; -import org.apache.servicecomb.saga.core.actors.messages.CompensationRecoveryMessage; -import org.apache.servicecomb.saga.core.actors.messages.TransactMessage; -import org.apache.servicecomb.saga.core.actors.messages.TransactionRecoveryMessage; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.scalatest.junit.JUnitSuite; - -import org.apache.servicecomb.saga.core.actors.messages.CompensateMessage; -import org.apache.servicecomb.saga.core.actors.messages.FailMessage; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.testkit.javadsl.TestKit; - -@SuppressWarnings("unchecked") -public class RequestActorTest extends JUnitSuite { - private final String parentRequestId1 = uniquify("parentRequestId1"); - private final String parentRequestId2 = uniquify("parentRequestId2"); - private final String requestId = uniquify("requestId"); - - private final SagaTask task = Mockito.mock(SagaTask.class); - private final SagaRequest request = Mockito.mock(SagaRequest.class, "request"); - private final SagaRequest request1 = Mockito.mock(SagaRequest.class, "request1"); - private final SagaRequest request2 = Mockito.mock(SagaRequest.class, "request2"); - private final SagaResponse response = Mockito.mock(SagaResponse.class); - private final FromJsonFormat> childrenExtractor = mock(FromJsonFormat.class); - - private final RequestActorContext context = new RequestActorContext(childrenExtractor); - - private final TransactionFailedException exception = new TransactionFailedException("oops"); - private static final ActorSystem actorSystem = ActorSystem.create(); - private final CompensateMessage compensateMessage = new CompensateMessage(new FailedSagaResponse(exception)); - - @Before - public void setUp() throws Exception { - when(childrenExtractor.fromJson(anyString())).thenReturn(emptySet()); - when(request.id()).thenReturn(requestId); - - when(request1.id()).thenReturn(parentRequestId1); - when(request2.id()).thenReturn(parentRequestId2); - } - - @AfterClass - public static void tearDown() throws Exception { - TestKit.shutdownActorSystem(actorSystem); - } - - @Test - public void tellNodeResponseToAllChildren() throws Exception { - new TestKit(actorSystem) {{ - addChildren(getRef()); - - ActorRef parent = someActor(); - context.addParent(requestId, parent); - - when(request.parents()).thenReturn(new String[] {parentRequestId1}); - when(task.commit(request, Operation.SUCCESSFUL_SAGA_RESPONSE)).thenReturn(response); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new TransactMessage(request1, Operation.SUCCESSFUL_SAGA_RESPONSE), parent); - - List responses = receiveN(2, duration("2 seconds")).stream() - .map(o -> ((TransactMessage) o).response()) - .collect(Collectors.toList()); - - assertThat(responses, containsInAnyOrder(response, response)); - - verify(task).commit(request, Operation.SUCCESSFUL_SAGA_RESPONSE); - }}; - } - - @Test - public void executeTransaction_OnlyWhenAllParentsResponsesAreReceived() throws Exception { - new TestKit(actorSystem) {{ - addChildren(getRef()); - - ActorRef parent1 = someActor(); - context.addParent(requestId, parent1); - - ActorRef parent2 = someActor(); - context.addParent(requestId, parent2); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SagaResponse.class); - - when(request.parents()).thenReturn(new String[] {parentRequestId1, parentRequestId2}); - when(task.commit(eq(request), argumentCaptor.capture())).thenReturn(response); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new TransactMessage(request1, Operation.SUCCESSFUL_SAGA_RESPONSE), parent1); - expectNoMsg(duration("500 milliseconds")); - - actorRef.tell(new TransactMessage(request2, SagaResponse.EMPTY_RESPONSE), parent2); - - List responses = receiveN(2, duration("2 seconds")).stream() - .map(o -> ((TransactMessage) o).response()) - .collect(Collectors.toList()); - - assertThat(responses, containsInAnyOrder(response, response)); - - SagaResponse response = argumentCaptor.getValue(); - assertThat(response, instanceOf(CompositeSagaResponse.class)); - assertThat(((CompositeSagaResponse) response).responses(), - Matchers.containsInAnyOrder(SagaResponse.EMPTY_RESPONSE, Operation.SUCCESSFUL_SAGA_RESPONSE)); - }}; - } - - @Test - public void tellAllRelativesToAbortOnError() throws Exception { - new TestKit(actorSystem) {{ - context.addChild(requestId, getRef()); - context.addActor(requestId, getRef()); - - context.addParent(requestId, getRef()); - - when(request.parents()).thenReturn(new String[] {parentRequestId1}); - when(task.commit(request, Operation.SUCCESSFUL_SAGA_RESPONSE)).thenThrow(exception); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new TransactMessage(request1, Operation.SUCCESSFUL_SAGA_RESPONSE), getRef()); - - List responses = receiveN(2, duration("2 seconds")).stream() - .map(o -> ((AbortMessage) o).response()) - .collect(Collectors.toList()); - - assertThat(responses, containsInAnyOrder(instanceOf(FailedSagaResponse.class), instanceOf(FailedSagaResponse.class))); - }}; - } - - @Test - public void tellAllRelativesExceptSenderToAbortOnAbort() throws Exception { - new TestKit(actorSystem) {{ - context.addChild(requestId, getRef()); - context.addActor(requestId, getRef()); - - context.addParent(requestId, getRef()); - - when(request.parents()).thenReturn(new String[] {parentRequestId1}); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new AbortMessage(exception), someActor()); - - List responses = receiveN(2, duration("2 seconds")).stream() - .map(o -> ((AbortMessage) o).response()) - .collect(Collectors.toList()); - - assertThat(responses, containsInAnyOrder(instanceOf(FailedSagaResponse.class), instanceOf(FailedSagaResponse.class))); - - actorRef.tell(new AbortMessage(exception), someActor()); - expectNoMsg(duration("500 milliseconds")); - }}; - } - - @Test - public void compensateIfTransactionIsCompleted() throws Exception { - new TestKit(actorSystem) {{ - addChildren(someActor()); - context.addParent(requestId, getRef()); - - when(request.parents()).thenReturn(new String[] {parentRequestId1}); - when(task.commit(request, Operation.SUCCESSFUL_SAGA_RESPONSE)).thenReturn(response); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new TransactMessage(request1, Operation.SUCCESSFUL_SAGA_RESPONSE), getRef()); - actorRef.tell(new AbortMessage(exception), noSender()); - actorRef.tell(compensateMessage, getRef()); - actorRef.tell(compensateMessage, getRef()); - - expectMsg(duration("2 seconds"), compensateMessage); - verify(task).compensate(request); - - // no duplicate compensation - reset(task); - actorRef.tell(compensateMessage, getRef()); - actorRef.tell(compensateMessage, getRef()); - expectNoMsg(duration("200 milliseconds")); - verify(task, never()).compensate(request); - }}; - } - - @Test - public void doNotCompensateIfTransactionIsNotCompleted() throws Exception { - new TestKit(actorSystem) {{ - addChildren(someActor()); - context.addParent(requestId, getRef()); - - when(request.parents()).thenReturn(new String[] {parentRequestId1}); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new AbortMessage(exception), noSender()); - actorRef.tell(compensateMessage, getRef()); - actorRef.tell(compensateMessage, getRef()); - - List responses = receiveN(2, duration("2 seconds")); - assertThat(responses, contains(instanceOf(AbortMessage.class), instanceOf(CompensateMessage.class))); - verify(task, never()).compensate(request); - - // no duplicate compensation - reset(task); - actorRef.tell(compensateMessage, getRef()); - actorRef.tell(compensateMessage, getRef()); - expectNoMsg(duration("200 milliseconds")); - verify(task, never()).compensate(request); - }}; - } - - @Test - public void skipIfActorIsNotChosenByAnyParent() throws Exception { - when(childrenExtractor.fromJson(Operation.SUCCESSFUL_SAGA_RESPONSE.body())).thenReturn(singleton("none")); - - new TestKit(actorSystem) {{ - addChildren(getRef()); - context.addParent(requestId, getRef()); - - when(request.parents()).thenReturn(new String[] {parentRequestId1}); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new TransactMessage(request1, Operation.SUCCESSFUL_SAGA_RESPONSE), getRef()); - - List responses = receiveN(2, duration("2 seconds")).stream() - .map(o -> ((TransactMessage) o).response()) - .collect(Collectors.toList()); - - assertThat(responses, Matchers.containsInAnyOrder(SagaResponse.NONE_RESPONSE, SagaResponse.NONE_RESPONSE)); - verify(task, never()).commit(request, Operation.SUCCESSFUL_SAGA_RESPONSE); - - // skip compensation for ignored actor - actorRef.tell(compensateMessage, getRef()); - actorRef.tell(compensateMessage, getRef()); - - expectMsg(duration("2 seconds"), compensateMessage); - verify(task, never()).compensate(request); - }}; - } - - @Test - public void transactIfChosenByAnyParent() throws Exception { - when(childrenExtractor.fromJson(Operation.SUCCESSFUL_SAGA_RESPONSE.body())).thenReturn(singleton(requestId)); - - new TestKit(actorSystem) {{ - addChildren(getRef()); - - ActorRef parent1 = someActor(); - context.addParent(requestId, parent1); - - ActorRef parent2 = someActor(); - context.addParent(requestId, parent2); - - when(request.parents()).thenReturn(new String[] {parentRequestId1, parentRequestId2}); - when(task.commit(eq(request), any(CompositeSagaResponse.class))).thenReturn(response); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new TransactMessage(request1, Operation.SUCCESSFUL_SAGA_RESPONSE), parent1); - actorRef.tell(new TransactMessage(request2, Operation.SUCCESSFUL_SAGA_RESPONSE), parent2); - - List responses = receiveN(2, duration("2 seconds")).stream() - .map(o -> ((TransactMessage) o).response()) - .collect(Collectors.toList()); - - assertThat(responses, containsInAnyOrder(response, response)); - }}; - } - - @Test - public void tellTransactionResponseToChildrenOnRecovery() throws Exception { - new TestKit(actorSystem) {{ - context.addChild(requestId, getRef()); - - ActorRef parent = someActor(); - context.addParent(requestId, parent); - - when(request.parents()).thenReturn(new String[] {parentRequestId1}); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new TransactionRecoveryMessage(response), noSender()); - actorRef.tell(new TransactMessage(request1, Operation.SUCCESSFUL_SAGA_RESPONSE), parent); - - List responses = receiveN(1, duration("2 seconds")).stream() - .map(o -> ((TransactMessage) o).response()) - .collect(Collectors.toList()); - - assertThat(responses, containsInAnyOrder(response)); - - verify(task, never()).commit(request, Operation.SUCCESSFUL_SAGA_RESPONSE); - }}; - } - - @Test - public void tellCompensationToParentsOnRecovery() throws Exception { - new TestKit(actorSystem) {{ - context.addChild(requestId, someActor()); - context.addParent(requestId, getRef()); - - when(request.parents()).thenReturn(new String[] {parentRequestId1}); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new AbortMessage(exception), someActor()); - actorRef.tell(new CompensationRecoveryMessage(), someActor()); - actorRef.tell(compensateMessage, someActor()); - - List responses = receiveN(2, duration("2 seconds")); - assertThat(responses, contains(instanceOf(AbortMessage.class), instanceOf(CompensateMessage.class))); - - verify(task, never()).compensate(request); - }}; - } - - @Test - public void abortOnPersistenceFailure() throws Exception { - new TestKit(actorSystem) {{ - context.addChild(requestId, noSender()); - context.addParent(requestId, getRef()); - - when(request.parents()).thenReturn(new String[] {parentRequestId1}); - - SagaStartFailedException oops = new SagaStartFailedException("oops", exception); - when(task.commit(request, SagaResponse.EMPTY_RESPONSE)).thenThrow(oops); - - ActorRef actorRef = actorSystem.actorOf(RequestActor.props(context, task, request)); - - actorRef.tell(new TransactMessage(request, SagaResponse.EMPTY_RESPONSE), getRef()); - - expectMsgClass(FailMessage.class); - }}; - } - - private ActorRef someActor() { - return actorSystem.actorOf(empty()); - } - - private void addChildren(ActorRef ref) { - context.addChild(requestId, ref); - context.addChild(requestId, ref); - context.addActor(requestId, ref); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/DirectedAcyclicGraphTraversalTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/DirectedAcyclicGraphTraversalTest.java deleted file mode 100644 index beb960769..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/DirectedAcyclicGraphTraversalTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import static java.util.Arrays.asList; -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.assertThat; - -import java.util.Collection; -import org.junit.Before; -import org.junit.Test; - -public class DirectedAcyclicGraphTraversalTest { - - private final Node root = new Node<>(0, "i don't care"); - private final Node node1 = new Node<>(1, "i don't care"); - private final Node node2 = new Node<>(2, "i don't care"); - private final Node node3 = new Node<>(3, "i don't care"); - private final Node node4 = new Node<>(4, "i don't care"); - private final Node node5 = new Node<>(5, "i don't care"); - private final Node leaf = new Node<>(6, "i don't care"); - - private final SingleLeafDirectedAcyclicGraph dag = new SingleLeafDirectedAcyclicGraph<>(root, leaf); - - // 0 - // / \ - // 1 \ - // / \ \ - // 3 4 2 - // \ / / - // 5 / - // \ / - // 6 - @Before - public void setUp() throws Exception { - root.addChildren(asList(node1, node2)); - node1.addChildren(asList(node3, node4)); - node3.addChild(node5); - node4.addChild(node5); - node5.addChild(leaf); - node2.addChild(leaf); - } - - @Test - public void traverseGraphOneLevelPerStepFromRoot() { - Traveller traveller = new ByLevelTraveller<>(dag, new FromRootTraversalDirection<>()); - - Collection> nodes = traveller.nodes(); - - traveller.next(); - assertThat(nodes, contains(root)); - - traveller.next(); - assertThat(nodes, contains(root, node1, node2)); - - traveller.next(); - assertThat(nodes, contains(root, node1, node2, node3, node4)); - - traveller.next(); - assertThat(nodes, contains(root, node1, node2, node3, node4, node5)); - - traveller.next(); - assertThat(nodes, contains(root, node1, node2, node3, node4, node5, leaf)); - } - - @Test - public void traverseGraphOneLevelPerStepFromLeaf() { - Traveller traveller = new ByLevelTraveller<>(dag, new FromLeafTraversalDirection<>()); - - Collection> nodes = traveller.nodes(); - - traveller.next(); - assertThat(nodes, contains(leaf)); - - traveller.next(); - assertThat(nodes, contains(leaf, node2, node5)); - - traveller.next(); - assertThat(nodes, contains(leaf, node2, node5, node3, node4)); - - traveller.next(); - assertThat(nodes, contains(leaf, node2, node5, node3, node4, node1)); - - traveller.next(); - assertThat(nodes, contains(leaf, node2, node5, node3, node4, node1, root)); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphBasedSagaExecutionComponentTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphBasedSagaExecutionComponentTest.java deleted file mode 100644 index 8515f93db..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphBasedSagaExecutionComponentTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import java.util.concurrent.Executors; - -import org.apache.servicecomb.saga.core.PersistentStore; -import org.apache.servicecomb.saga.core.SagaExecutionComponentTestBase; -import org.apache.servicecomb.saga.core.application.SagaFactory; - - -public class GraphBasedSagaExecutionComponentTest extends SagaExecutionComponentTestBase { - - @Override - protected SagaFactory sagaFactory(PersistentStore eventStore) { - return new GraphBasedSagaFactory(500, eventStore, null, Executors.newFixedThreadPool(5)); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphBuilderTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphBuilderTest.java deleted file mode 100644 index 8703c7a22..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphBuilderTest.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static org.apache.servicecomb.saga.core.Operation.TYPE_REST; -import static java.util.Collections.emptyMap; -import static java.util.Collections.emptySet; -import static java.util.Collections.singleton; -import static org.hamcrest.CoreMatchers.startsWith; -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.when; - -import java.util.Collection; -import java.util.stream.Collectors; - -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.SagaException; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaRequestImpl; -import org.hamcrest.collection.IsIterableContainingInOrder; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import org.apache.servicecomb.saga.core.CompensationImpl; -import org.apache.servicecomb.saga.core.TransactionImpl; - -@SuppressWarnings("unchecked") -public class GraphBuilderTest { - - private final SagaRequest request1 = new SagaRequestImpl( - "request-aaa", - "aaa", - TYPE_REST, - new TransactionImpl("/rest/as", "post", emptyMap()), - new CompensationImpl("/rest/as","delete", emptyMap()) - ); - - private final SagaRequest request2 = new SagaRequestImpl( - "request-bbb", - "bbb", - TYPE_REST, - new TransactionImpl("/rest/bs", "post", emptyMap()), - new CompensationImpl("/rest/bs","delete", emptyMap()) - ); - - private final SagaRequest request3 = new SagaRequestImpl( - "request-ccc", - "ccc", - TYPE_REST, - new TransactionImpl("/rest/cs", "post", emptyMap()), - new CompensationImpl("/rest/cs","delete", emptyMap()), - null, - new String[]{"request-aaa", "request-bbb"} - ); - private final SagaRequest[] requests = {request1, request2, request3}; - - private final SagaRequest duplicateRequest = new SagaRequestImpl( - "request-duplicate-id", - "xxx", - TYPE_REST, - new TransactionImpl("/rest/xs", "post", emptyMap()), - new CompensationImpl("/rest/xs","delete", emptyMap()) - ); - private final SagaRequest[] duplicateRequests = {duplicateRequest, duplicateRequest}; - - private final GraphCycleDetector detector = Mockito.mock(GraphCycleDetector.class); - private final GraphBuilder graphBuilder = new GraphBuilder(detector); - - @Before - public void setUp() throws Exception { - when(detector.cycleJoints(any())).thenReturn(emptySet()); - } - - @Test - public void buildsGraphOfParallelRequests() { - SingleLeafDirectedAcyclicGraph tasks = graphBuilder.build(requests); - - Traveller traveller = new ByLevelTraveller<>(tasks, new FromRootTraversalDirection<>()); - Collection> nodes = traveller.nodes(); - - traveller.next(); - assertThat(requestsOf(nodes), IsIterableContainingInOrder.contains(NoOpSagaRequest.SAGA_START_REQUEST)); - nodes.clear(); - - traveller.next(); - assertThat(requestsOf(nodes), contains(request1, request2)); - nodes.clear(); - - traveller.next(); - assertThat(requestsOf(nodes), contains(request3)); - nodes.clear(); - - traveller.next(); - assertThat(requestsOf(nodes), IsIterableContainingInOrder.contains(NoOpSagaRequest.SAGA_END_REQUEST)); - } - - @Test - public void blowsUpWhenJsonContainsDuplicateRequestId() { - try { - graphBuilder.build(duplicateRequests); - fail(SagaException.class.getSimpleName() + " is expected, but none thrown"); - } catch (SagaException e) { - assertThat(e.getMessage(), - is("Failed to interpret requests with duplicate request id: request-duplicate-id")); - } - } - - @Test - public void blowsUpWhenGraphContainsCycle() { - reset(detector); - when(detector.cycleJoints(any())).thenReturn(singleton(new Node<>(0L, null))); - - try { - graphBuilder.build(requests); - expectFailing(SagaException.class); - } catch (SagaException e) { - assertThat(e.getMessage(), startsWith("Cycle detected in the request graph at nodes ")); - } - } - - private Collection requestsOf(Collection> nodes) { - return nodes.stream() - .map(Node::value) - .collect(Collectors.toList()); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetectorTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetectorTest.java deleted file mode 100644 index 934c54b6d..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/GraphCycleDetectorTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import java.util.Set; -import org.junit.Before; -import org.junit.Test; - -@SuppressWarnings("unchecked") -public class GraphCycleDetectorTest { - - private final Node root = node(0); - private final Node leaf = node(Long.MAX_VALUE); - - private final Node node1 = node(1); - private final Node node2 = node(2); - private final Node node3 = node(3); - - private final SingleLeafDirectedAcyclicGraph graph = new SingleLeafDirectedAcyclicGraph<>(root, leaf); - private final GraphCycleDetector detector = new GraphCycleDetectorImpl<>(); - - @Before - public void setUp() throws Exception { - root.addChild(node1); - - node2.addChild(leaf); - node3.addChild(leaf); - } - - @Test - public void emptyNodesWhenNoCycleInGraph() { - node1.addChild(node2); - node1.addChild(node3); - - Set> nodes = detector.cycleJoints(graph); - - assertThat(nodes.isEmpty(), is(true)); - } - - @Test - public void nonEmptyNodesIfGraphContainsCycle() { - node1.addChild(node2); - node2.addChild(node3); - node3.addChild(node1); - - Set> nodes = detector.cycleJoints(graph); - - assertThat(nodes, contains(node1)); - } - - private Node node(long id) { - return new Node<>(id, "value " + id); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/NodeTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/NodeTest.java deleted file mode 100644 index 2da4ba0b3..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/core/dag/NodeTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core.dag; - -import static java.util.Arrays.asList; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import org.junit.Before; -import org.junit.Test; - -public class NodeTest { - - - private final Node parent = new Node<>(0, "i don't care"); - private final Node node1 = new Node<>(1, "i don't care"); - private final Node node2 = new Node<>(2, "i don't care"); - private final Node node3 = new Node<>(3, "i don't care"); - private final Node node4 = new Node<>(4, "i don't care"); - private final Node node5 = new Node<>(5, "i don't care"); - private final Node node6 = new Node<>(6, "i don't care"); - - // 0 - // / \ - // 1 \ - // / \ \ - // 3 4 2 - // \ / / - // 5 / - // \ / - // 6 - @Before - public void setUp() throws Exception { - parent.addChildren(asList(node1, node2)); - node1.addChildren(asList(node3, node4)); - node3.addChild(node5); - node4.addChild(node5); - node5.addChild(node6); - node2.addChild(node6); - } - - @Test - public void nodeIsLinkedBidirectionally() { - assertThat(parent.children(), containsInAnyOrder(node1, node2)); - assertThat(node1.parents(), contains(parent)); - assertThat(node1.children(), containsInAnyOrder(node3, node4)); - - assertThat(node2.parents(), contains(parent)); - assertThat(node2.children(), contains(node6)); - - assertThat(node3.parents(), contains(node1)); - assertThat(node3.children(), contains(node5)); - - assertThat(node4.parents(), contains(node1)); - assertThat(node4.children(), contains(node5)); - - assertThat(node5.parents(), containsInAnyOrder(node3, node4)); - assertThat(node5.children(), contains(node6)); - - assertThat(node6.parents(), containsInAnyOrder(node2, node5)); - assertThat(node6.children().isEmpty(), is(true)); - } -} diff --git a/saga-core/src/test/java/org/apache/servicecomb/saga/infrastructure/ContextAwareEventStoreTest.java b/saga-core/src/test/java/org/apache/servicecomb/saga/infrastructure/ContextAwareEventStoreTest.java deleted file mode 100644 index 1216e5f14..000000000 --- a/saga-core/src/test/java/org/apache/servicecomb/saga/infrastructure/ContextAwareEventStoreTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.infrastructure; - -import static org.mockito.Mockito.verify; - -import org.apache.servicecomb.saga.core.EventStore; -import org.junit.Test; -import org.mockito.Mockito; - -import org.apache.servicecomb.saga.core.SagaContext; -import org.apache.servicecomb.saga.core.SagaEvent; - -public class ContextAwareEventStoreTest { - private final EventStore underlying = Mockito.mock(EventStore.class); - private final SagaContext context = Mockito.mock(SagaContext.class); - private final SagaEvent sagaEvent = Mockito.mock(SagaEvent.class); - - private final ContextAwareEventStore contextAwareEventStore = new ContextAwareEventStore(underlying, context); - - @Test - public void persistWithUnderlyingStore() throws Exception { - contextAwareEventStore.offer(sagaEvent); - - verify(sagaEvent).gatherTo(context); - verify(underlying).offer(sagaEvent); - } -} diff --git a/saga-core/src/test/resources/application.conf b/saga-core/src/test/resources/application.conf deleted file mode 100644 index 0629dd633..000000000 --- a/saga-core/src/test/resources/application.conf +++ /dev/null @@ -1,21 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -akka { - loggers = ["akka.event.slf4j.Slf4jLogger"] - loglevel = "DEBUG" - logging-filter = "akka.event.slf4j.Slf4jLoggingFilter" -} diff --git a/saga-core/src/test/resources/log4j2.xml b/saga-core/src/test/resources/log4j2.xml deleted file mode 100644 index cae04cb93..000000000 --- a/saga-core/src/test/resources/log4j2.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/saga-demo/conditional-transaction-demo/README.md b/saga-demo/conditional-transaction-demo/README.md deleted file mode 100755 index 9ae1deb65..000000000 --- a/saga-demo/conditional-transaction-demo/README.md +++ /dev/null @@ -1,174 +0,0 @@ -# Conditional Transaction Demo -This demo simulates a partial backend of an e-commerce application including four services: -* payment -* membership -* inventory -* supplier - -**Note** Please go through the dependency-free-transaction-demo first, before proceeding with this demo. - -## Background -Many e-commerce sites have membership concept, which will level up when a customer makes a certain amount of purchase. -Moreover, as goods are sold and the stock drops to a certain level, the e-commerce company needs to fetch more goods from -its suppliers. Both scenarios introduce conditional transactions. - -## Workflow -``` - /---> if total purchase >= 1K, level up membership -start ---> make payment ---> dispatch product from inventory ---> end - \---> if product stock < 10, replenish product from supplier -``` -The conditions are business logic and belong to business service. Therefore, the decision to level up membership is made -in payment service and the decision to replenish products is made in inventory service. Saga is to be informed of service -decision by adding an additional element `sagaChildren` in service response JSON to indicate which services are to be invoked -next as shown below. -```json -{ - "customerId": "mike", - "body": "Payment made with id xxx for customer mike", - "sagaChildren": ["inventory"] -} -``` - -If `sagaChildren` is empty or not provided in service response, saga will invoke all of its child services. To invoke none -of them, explicitly return `"sagaChildren": ["none"]`. - -If any of the sub-transaction specified in sagaChildren fails, all completed sub-transactions will be compensated as usual, -when the recovery policy if backward recovery. - -## Running Demo -1. run the following command to create docker images in saga project root folder. -``` -mvn package -DskipTests -Pdocker -Pdemo -``` - -2. start application up in saga/saga-demo/conditional-transaction-demo with the following command -``` -docker-compose up -``` - -## User Requests -The request JSON to ensure the workflow order looks like the following: -```json -{ - "policy": "BackwardRecovery", - "requests": [ - { - "id": "payment", - "type": "rest", - "serviceName": "payment.servicecomb.io:8080", - "transaction": { - "method": "post", - "path": "/payment", - "params": { - "form": { - "customerId": "mike", - "purchaseAmount": 400 - } - } - }, - "compensation": { - "method": "put", - "path": "/payment", - "params": { - "form": { - "customerId": "mike" - } - } - } - }, - { - "id": "membership", - "type": "rest", - "serviceName": "membership.servicecomb.io:8080", - "parents": [ - "payment" - ], - "transaction": { - "method": "post", - "path": "/membership", - "params": { - "form": { - "customerId": "mike" - } - } - }, - "compensation": { - "method": "put", - "path": "/membership", - "params": { - "form": { - "customerId": "mike" - } - } - } - }, - { - "id": "inventory", - "type": "rest", - "serviceName": "inventory.servicecomb.io:8080", - "parents": [ - "payment" - ], - "transaction": { - "method": "post", - "path": "/inventory", - "params": { - "form": { - "customerId": "mike" - } - } - }, - "compensation": { - "method": "put", - "path": "/inventory", - "params": { - "form": { - "customerId": "mike" - } - } - } - }, - { - "id": "supplier", - "type": "rest", - "serviceName": "supplier.servicecomb.io:8080", - "parents": [ - "inventory" - ], - "transaction": { - "method": "post", - "path": "/supplier", - "params": { - "form": { - "customerId": "servicecomb_mall" - } - } - }, - "compensation": { - "method": "put", - "path": "/supplier", - "params": { - "form": { - "customerId": "servicecomb_mall" - } - } - } - } - ] -} - -``` - -To send the above JSON request to Saga, use [postman](https://www.getpostman.com/postman) with POST request to url `http://:8083/requests` - -Each request to payment service will increase user mike's total purchase by $400. The 3rd request will trigger -membership level up. - -The initial product stock is 11 in inventory and each request to inventory service will deduct product stock by 1. -So the 2nd request will trigger product replenishment from supplier. - -**Note** transactions and compensations implemented by services must be idempotent. In this demo, we did not enforce that -for simplicity. - -To see all events generated by Saga, visit `http://:8083/events` with postman. diff --git a/saga-demo/conditional-transaction-demo/conditional-transaction-demo-tests/pom.xml b/saga-demo/conditional-transaction-demo/conditional-transaction-demo-tests/pom.xml deleted file mode 100644 index ffe53b19e..000000000 --- a/saga-demo/conditional-transaction-demo/conditional-transaction-demo-tests/pom.xml +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - conditional-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - conditional-transaction-demo-tests - Saga::Demo::Conditional Transaction::Tests - - - - - commons-logging - commons-logging - 1.2 - - - io.rest-assured - rest-assured - test - - - junit - junit - test - - - org.codehaus.groovy - groovy-all - test - - - - - - - io.fabric8 - docker-maven-plugin - - - - postgres - postgres - - - saga - saga - password - - - database system is ready to accept connections - - - 5432 - - - - - - postgres.port:5432 - - - - - payment:${project.version} - payment - - - - - - Tomcat started on port - - - 8080 - - - - - - payment.port:8080 - - - - - membership:${project.version} - membership - - - - - - Tomcat started on port - - - 8080 - - - - - - membership.port:8080 - - - - - inventory:${project.version} - inventory - - - - - - Tomcat started on port - - - 8080 - - - - - - inventory.port:8080 - - - - - supplier:${project.version} - supplier - - - - - - Tomcat started on port - - - 8080 - - - - - - supplier.port:8080 - - - - - saga-spring:${project.version} - saga - - - - -Dspring.profiles.active=prd -Dspring.main.webEnvironment=true - - - - postgres:postgres.servicecomb.io - payment:payment.servicecomb.io - membership:membership.servicecomb.io - inventory:inventory.servicecomb.io - supplier:supplier.servicecomb.io - - - Tomcat started on port - - - 8080 - - - - - - saga.port:8080 - - - postgres - - - - - - - - start - pre-integration-test - - start - - - - stop - post-integration-test - - stop - - - - - - - - - docker - - - - org.codehaus.gmaven - gmaven-plugin - - - add-default-properties - initialize - - execute - - - - project.properties.setProperty('docker.hostname', 'localhost') - log.info("Docker hostname is " + project.properties['docker.hostname']) - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${maven.failsafe.version} - - - - http://${docker.hostname}:${saga.port} - - - ${jacoco.failsafe.argLine} - - - - - integration-test - verify - - - - - - - - - docker-machine - - - - org.codehaus.gmaven - gmaven-plugin - - - add-dynamic-properties - prepare-package - - execute - - - - def process = "docker-machine ip default".execute() - process.waitFor() - project.properties.setProperty('docker.hostname', process.in.text.trim()) - - log.info("Docker hostname is " + project.properties['docker.hostname']) - - - - - - - - - - - diff --git a/saga-demo/conditional-transaction-demo/conditional-transaction-demo-tests/src/test/java/org/apache/servicecomb/saga/demo/tests/ConditionalTransactionIT.java b/saga-demo/conditional-transaction-demo/conditional-transaction-demo-tests/src/test/java/org/apache/servicecomb/saga/demo/tests/ConditionalTransactionIT.java deleted file mode 100644 index d1734d59a..000000000 --- a/saga-demo/conditional-transaction-demo/conditional-transaction-demo-tests/src/test/java/org/apache/servicecomb/saga/demo/tests/ConditionalTransactionIT.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.tests; - -import static io.restassured.RestAssured.given; -import static io.restassured.http.ContentType.TEXT; -import static org.hamcrest.core.Is.is; - -import org.junit.BeforeClass; -import org.junit.Test; - -public class ConditionalTransactionIT { - - private static final String requests = "{\n" - + " \"policy\": \"BackwardRecovery\",\n" - + " \"requests\": [\n" - + " {\n" - + " \"id\": \"payment\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"payment.servicecomb.io:8080\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/payment\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\",\n" - + " \"purchaseAmount\": 400\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"put\",\n" - + " \"path\": \"/payment\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " }\n" - + " },\n" - + " {\n" - + " \"id\": \"membership\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"membership.servicecomb.io:8080\",\n" - + " \"parents\": [\n" - + " \"payment\"\n" - + " ],\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/membership\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"put\",\n" - + " \"path\": \"/membership\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " }\n" - + " },\n" - + " {\n" - + " \"id\": \"inventory\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"inventory.servicecomb.io:8080\",\n" - + " \"parents\": [\n" - + " \"payment\"\n" - + " ],\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/inventory\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"put\",\n" - + " \"path\": \"/inventory\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " }\n" - + " },\n" - + " {\n" - + " \"id\": \"supplier\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"supplier.servicecomb.io:8080\",\n" - + " \"parents\": [\n" - + " \"inventory\"\n" - + " ],\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/supplier\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"servicecomb_mall\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"put\",\n" - + " \"path\": \"/supplier\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"servicecomb_mall\"\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " ]\n" - + "}\n"; - - private static String sagaAddress; - - @BeforeClass - public static void setUp() throws Exception { - sagaAddress = System.getProperty("saga.address"); - } - - @Test - public void ableToSendRequestsToServicesThroughSaga() { - given() - .contentType(TEXT) - .body(requests) - .when() - .post(sagaAddress + "/requests") - .then() - .statusCode(is(200)) - .body(is("success")); - } -} diff --git a/saga-demo/conditional-transaction-demo/docker-compose.yaml b/saga-demo/conditional-transaction-demo/docker-compose.yaml deleted file mode 100755 index 45c72c3ef..000000000 --- a/saga-demo/conditional-transaction-demo/docker-compose.yaml +++ /dev/null @@ -1,75 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -version: '2.1' - -services: - postgres: - image: "postgres" - hostname: postgres - environment: - - POSTGRES_DB=saga - - POSTGRES_USER=saga - - POSTGRES_PASSWORD=password - ports: - - "5432:5432" - healthcheck: - test: ["CMD-SHELL", "nc -z localhost 5432 &> /dev/null; echo $$?"] - interval: 30s - timeout: 10s - retries: 5 - - payment: - image: "payment:0.0.3-SNAPSHOT" - hostname: payment - ports: - - "8080" - - membership: - image: "membership:0.0.3-SNAPSHOT" - hostname: membership - ports: - - "8080" - - inventory: - image: "inventory:0.0.3-SNAPSHOT" - hostname: inventory - ports: - - "8080" - - supplier: - image: "supplier:0.0.3-SNAPSHOT" - hostname: supplier - ports: - - "8080" - - saga: - image: "saga-spring:0.0.3-SNAPSHOT" - hostname: saga - links: - - "postgres:postgres.servicecomb.io" - - "payment:payment.servicecomb.io" - - "membership:membership.servicecomb.io" - - "inventory:inventory.servicecomb.io" - - "supplier:supplier.servicecomb.io" - environment: - - JAVA_OPTS=-Dspring.profiles.active=prd -Dspring.main.webEnvironment=true - ports: - - "8083:8080" - depends_on: - postgres: - condition: service_healthy diff --git a/saga-demo/conditional-transaction-demo/inventory/pom.xml b/saga-demo/conditional-transaction-demo/inventory/pom.xml deleted file mode 100644 index 281ea3470..000000000 --- a/saga-demo/conditional-transaction-demo/inventory/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - conditional-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - inventory - Saga::Demo::Conditional Transaction::Inventory - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - - diff --git a/saga-demo/conditional-transaction-demo/inventory/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryApplication.java b/saga-demo/conditional-transaction-demo/inventory/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryApplication.java deleted file mode 100644 index f0b8e68dc..000000000 --- a/saga-demo/conditional-transaction-demo/inventory/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.inventory; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class InventoryApplication { - - public static void main(String[] args) { - SpringApplication.run(InventoryApplication.class, args); - } -} diff --git a/saga-demo/conditional-transaction-demo/inventory/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryController.java b/saga-demo/conditional-transaction-demo/inventory/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryController.java deleted file mode 100644 index 1f829555b..000000000 --- a/saga-demo/conditional-transaction-demo/inventory/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryController.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.inventory; - -import static org.springframework.http.HttpStatus.BAD_REQUEST; -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -import java.io.IOException; -import java.util.UUID; - -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; - -@Controller -@RequestMapping("/") -public class InventoryController { - private static final int FETCH_THRESHOLD = 10; - private static final String CUSTOMER_ID = "customerId"; - private final ObjectMapper objectMapper = new ObjectMapper(); - - private int stock = 11; - - @RequestMapping(value = "inventory", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity dispatch(@RequestParam String response) { - try { - ObjectNode jsonNodes = objectMapper.readValue(response, ObjectNode.class); - if (jsonNodes.has(CUSTOMER_ID)) { - String customerId = jsonNodes.get(CUSTOMER_ID).textValue(); - - stock--; - if (isStockShort()) { - // when no sagaChildren is provided, all child sub-transaction of inventory will be run - return response(customerId, ""); - } - - // select no child sub-transaction to run next, by specifying none in sagaChildren - return response(customerId,", \"sagaChildren\": [\"none\"] \n"); - } - return new ResponseEntity<>("Customer Id is missing", BAD_REQUEST); - } catch (IOException e) { - return new ResponseEntity<>(e.getMessage(), INTERNAL_SERVER_ERROR); - } - } - - @RequestMapping(value = "inventory", method = PUT, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity recall(@RequestParam String customerId) { - stock++; - return ResponseEntity.ok(String.format("Dispatch recalled with id %s for customer %s", - UUID.randomUUID().toString(), - customerId)); - } - - private ResponseEntity response(String customerId, String optionalSagaChildren) { - return ResponseEntity.ok(String.format("{\n" - + " \"body\": \"Goods dispatched with id %s for customer %s\"\n" - + optionalSagaChildren - + "}", - UUID.randomUUID().toString(), - customerId)); - } - - private boolean isStockShort() { - return stock < FETCH_THRESHOLD; - } -} diff --git a/saga-demo/conditional-transaction-demo/inventory/src/test/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryControllerTest.java b/saga-demo/conditional-transaction-demo/inventory/src/test/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryControllerTest.java deleted file mode 100644 index d58a6100f..000000000 --- a/saga-demo/conditional-transaction-demo/inventory/src/test/java/org/apache/servicecomb/saga/demo/conditional/transaction/inventory/InventoryControllerTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.inventory; - -import static org.hamcrest.core.Is.is; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -@RunWith(SpringRunner.class) -@WebMvcTest(InventoryController.class) -public class InventoryControllerTest { - private static final String content = "response=" + encode("{\n" - + " \"customerId\": \"mike\",\n" - + " \"foo\": \"bar\"\n" - + "}"); - - private static String encode(String param) { - try { - return URLEncoder.encode(param, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException(e); - } - } - - @Autowired - private MockMvc mockMvc; - - @Test - public void respondWithChildren_IfStockIsLowerThanThreshold() throws Exception { - mockMvc.perform(post("/inventory") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .content(content)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.sagaChildren[0]", is("none"))); - - mockMvc.perform(post("/inventory") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .content(content)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.sagaChildren[0]").doesNotExist()); - } - - @Test - public void badRequestIfCustomerIdIsNotInRequestContent() throws Exception { - String content = "response=" + encode("{}"); - - mockMvc.perform(post("/inventory") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .content(content)) - .andExpect(status().isBadRequest()); - } -} diff --git a/saga-demo/conditional-transaction-demo/membership/pom.xml b/saga-demo/conditional-transaction-demo/membership/pom.xml deleted file mode 100644 index b219945a1..000000000 --- a/saga-demo/conditional-transaction-demo/membership/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - conditional-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - membership - Saga::Demo::Conditional Transaction::Membership - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - diff --git a/saga-demo/conditional-transaction-demo/membership/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/membership/MembershipApplication.java b/saga-demo/conditional-transaction-demo/membership/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/membership/MembershipApplication.java deleted file mode 100644 index 4be730010..000000000 --- a/saga-demo/conditional-transaction-demo/membership/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/membership/MembershipApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.membership; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class MembershipApplication { - - public static void main(String[] args) { - SpringApplication.run(MembershipApplication.class, args); - } -} diff --git a/saga-demo/conditional-transaction-demo/membership/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/membership/MembershipController.java b/saga-demo/conditional-transaction-demo/membership/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/membership/MembershipController.java deleted file mode 100644 index f7efc3934..000000000 --- a/saga-demo/conditional-transaction-demo/membership/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/membership/MembershipController.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.membership; - -import static java.util.Collections.singleton; -import static org.springframework.http.HttpStatus.FORBIDDEN; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -import java.util.Set; - -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -@Controller -@RequestMapping("/") -public class MembershipController { - - private final Set customers = singleton("mike"); - - @RequestMapping(value = "membership", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity levelUp(@RequestParam String customerId) { - if (!customers.contains(customerId)) { - return new ResponseEntity<>("No such customer with id " + customerId, FORBIDDEN); - } - - return ResponseEntity.ok(String.format("{\n" - + " \"body\": \"Level up customer %s to silver member\"\n" - + "}", - customerId)); - } - - @RequestMapping(value = "membership", method = PUT, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity levelDown(@RequestParam String customerId) { - if (!customers.contains(customerId)) { - return new ResponseEntity<>("No such customer with id " + customerId, FORBIDDEN); - } - - return ResponseEntity.ok(String.format("Level down customer %s to bronze member", - customerId)); - } - -} diff --git a/saga-demo/conditional-transaction-demo/payment/pom.xml b/saga-demo/conditional-transaction-demo/payment/pom.xml deleted file mode 100644 index 1792916b5..000000000 --- a/saga-demo/conditional-transaction-demo/payment/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - conditional-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - payment - Saga::Demo::Conditional Transaction::Payment - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - - diff --git a/saga-demo/conditional-transaction-demo/payment/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentApplication.java b/saga-demo/conditional-transaction-demo/payment/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentApplication.java deleted file mode 100644 index 7e0a643bb..000000000 --- a/saga-demo/conditional-transaction-demo/payment/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.payment; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class PaymentApplication { - - public static void main(String[] args) { - SpringApplication.run(PaymentApplication.class, args); - } -} diff --git a/saga-demo/conditional-transaction-demo/payment/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentController.java b/saga-demo/conditional-transaction-demo/payment/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentController.java deleted file mode 100644 index 531414b07..000000000 --- a/saga-demo/conditional-transaction-demo/payment/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentController.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.payment; - -import static java.util.Collections.singletonMap; -import static org.springframework.http.HttpStatus.FORBIDDEN; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -@Controller -@RequestMapping("/") -public class PaymentController { - private static final int UPGRADE_THRESHOLD = 1000; - - private final Map customerPurchases = new HashMap<>(singletonMap("mike", 0)); - - @RequestMapping(value = "payment", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity purchase(@RequestParam String customerId, @RequestParam int purchaseAmount) { - if (!customerPurchases.containsKey(customerId)) { - return new ResponseEntity<>("No such customer with id " + customerId, FORBIDDEN); - } - - customerPurchases.compute(customerId, (id, purchases) -> purchases + purchaseAmount); - - if (isUpgradable(customerId)) { - // when no sagaChildren is provided, all child sub-transaction of payment will be run - return response(customerId, ""); - } - - // select only sub-transaction of inventory service to run next, by specifying inventory in sagaChildren - return response(customerId, ", \"sagaChildren\": [\"inventory\"] \n"); - } - - @RequestMapping(value = "payment", method = PUT, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity refund(@RequestParam String customerId) { - if (!customerPurchases.containsKey(customerId)) { - return new ResponseEntity<>("No such customer with id " + customerId, FORBIDDEN); - } - - return ResponseEntity.ok(String.format("Payment refunded with id %s for customer %s", - UUID.randomUUID().toString(), - customerId)); - } - - private ResponseEntity response(String customerId, String optionalSagaChildren) { - return ResponseEntity.ok(String.format("{\n" - + " \"customerId\": \"mike\",\n" - + " \"body\": \"Payment made with id %s for customer %s\"\n" - + optionalSagaChildren - + "}", - UUID.randomUUID().toString(), - customerId)); - } - - private boolean isUpgradable(String customerId) { - return customerPurchases.get(customerId) >= UPGRADE_THRESHOLD; - } -} diff --git a/saga-demo/conditional-transaction-demo/payment/src/test/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentControllerTest.java b/saga-demo/conditional-transaction-demo/payment/src/test/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentControllerTest.java deleted file mode 100644 index 99e61871e..000000000 --- a/saga-demo/conditional-transaction-demo/payment/src/test/java/org/apache/servicecomb/saga/demo/conditional/transaction/payment/PaymentControllerTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.payment; - -import static org.hamcrest.core.Is.is; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -@RunWith(SpringRunner.class) -@WebMvcTest(PaymentController.class) -public class PaymentControllerTest { - private static final String requestContent = "customerId=mike&purchaseAmount=400"; - - @Autowired - private MockMvc mockMvc; - - @Test - public void respondWithChildren_IfTotalPurchaseIsLowerThanThreshold() throws Exception { - mockMvc.perform(post("/payment") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .content(requestContent)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.sagaChildren[0]", is("inventory"))); - - mockMvc.perform(post("/payment") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .content(requestContent)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.sagaChildren[0]", is("inventory"))); - - mockMvc.perform(post("/payment") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .content(requestContent)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.sagaChildren[0]").doesNotExist()); - } -} diff --git a/saga-demo/conditional-transaction-demo/pom.xml b/saga-demo/conditional-transaction-demo/pom.xml deleted file mode 100644 index 97fe09017..000000000 --- a/saga-demo/conditional-transaction-demo/pom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - saga-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - conditional-transaction-demo - Saga::Demo::Conditional Transaction - pom - - - payment - membership - inventory - supplier - conditional-transaction-demo-tests - - - - diff --git a/saga-demo/conditional-transaction-demo/supplier/pom.xml b/saga-demo/conditional-transaction-demo/supplier/pom.xml deleted file mode 100644 index e5c596479..000000000 --- a/saga-demo/conditional-transaction-demo/supplier/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - conditional-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - supplier - Saga::Demo::Conditional Transaction::Supplier - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - diff --git a/saga-demo/conditional-transaction-demo/supplier/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/supplier/SupplierApplication.java b/saga-demo/conditional-transaction-demo/supplier/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/supplier/SupplierApplication.java deleted file mode 100644 index e6729d921..000000000 --- a/saga-demo/conditional-transaction-demo/supplier/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/supplier/SupplierApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.supplier; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SupplierApplication { - - public static void main(String[] args) { - SpringApplication.run(SupplierApplication.class, args); - } -} diff --git a/saga-demo/conditional-transaction-demo/supplier/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/supplier/SupplierController.java b/saga-demo/conditional-transaction-demo/supplier/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/supplier/SupplierController.java deleted file mode 100644 index bd71070c5..000000000 --- a/saga-demo/conditional-transaction-demo/supplier/src/main/java/org/apache/servicecomb/saga/demo/conditional/transaction/supplier/SupplierController.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.conditional.transaction.supplier; - -import static java.util.Collections.singleton; -import static org.springframework.http.HttpStatus.FORBIDDEN; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; - -import java.util.Set; -import java.util.UUID; - -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -@Controller -@RequestMapping("/") -public class SupplierController { - - private final Set customers = singleton("servicecomb_mall"); - - @RequestMapping(value = "supplier", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity supply(@RequestParam String customerId) { - if (!customers.contains(customerId)) { - return new ResponseEntity<>("No such customer with id " + customerId, FORBIDDEN); - } - - return ResponseEntity.ok(String.format("{\n" - + " \"body\": \"Goods supply with id %s on the way for customer %s\"\n" - + "}", - UUID.randomUUID().toString(), - customerId)); - } -} diff --git a/saga-demo/conditional-transaction-demo/supplier/src/main/resources/META-INF/LICENSE.txt b/saga-demo/conditional-transaction-demo/supplier/src/main/resources/META-INF/LICENSE.txt deleted file mode 100644 index d64569567..000000000 --- a/saga-demo/conditional-transaction-demo/supplier/src/main/resources/META-INF/LICENSE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/saga-demo/conditional-transaction-demo/supplier/src/main/resources/META-INF/NOTICE.txt b/saga-demo/conditional-transaction-demo/supplier/src/main/resources/META-INF/NOTICE.txt deleted file mode 100644 index 2e215bf2e..000000000 --- a/saga-demo/conditional-transaction-demo/supplier/src/main/resources/META-INF/NOTICE.txt +++ /dev/null @@ -1,11 +0,0 @@ - ========================================================================= - == NOTICE file corresponding to the section 4 d of == - == the Apache License, Version 2.0, == - == in this case for the Apache Camel distribution. == - ========================================================================= - - This product includes software developed by - The Apache Software Foundation (http://www.apache.org/). - - Please read the different LICENSE files present in the licenses directory of - this distribution. diff --git a/saga-demo/dependency-free-transaction-demo/README.md b/saga-demo/dependency-free-transaction-demo/README.md deleted file mode 100755 index 611dfa5e6..000000000 --- a/saga-demo/dependency-free-transaction-demo/README.md +++ /dev/null @@ -1,168 +0,0 @@ -# Dependency Free Transaction Demo -This demo simulates a bare minimal travel application including four services: -* car rental -* flight booking -* hotel reservation -* payment - -## Background -A user with travel plans may like making car rental, flight booking, and hotel reservation with just a single service -instead of three separate services. That's why this application can help. - -With microservice architecture, each of the services may have its own database technology and it's not feasible to ensure -all transactions on these services are either committed or rolled back with database. In this demo, we make use of Saga to -ensure eventual data consistency among services. - -## Architecture - -``` - - /----> car rental service -User ---> Saga -----> flight booking service - \----> hotel reservation service - \---> payment service -``` - -## Running Demo -1. run the following command to create docker images in saga project root folder. -``` -mvn package -DskipTests -Pdocker -Pdemo -``` - -2. start application up in saga/saga-demo/dependency-free-transaction-demo with the following command -``` -docker-compose up -``` - -## User Requests -A user normally expects to make payment only when transactions with all three services are completed successfully. So Saga -will talk to car rental, flight booking, and hotel reservation services in parallel and then payment service only when the -former three services return success. - -The request JSON to ensure this process order looks like the following: -```json -{ - "policy": "BackwardRecovery", - "requests": [ - { - "id": "request-car", - "type": "rest", - "serviceName": "car-rental-service", - "transaction": { - "method": "post", - "path": "/rentals", - "params": { - "form": { - "customerId": "mike" - } - } - }, - "compensation": { - "method": "put", - "path": "/rentals", - "params": { - "form": { - "customerId": "mike" - } - } - } - }, - { - "id": "request-hotel", - "type": "rest", - "serviceName": "hotel-reservation-service", - "transaction": { - "method": "post", - "path": "/reservations", - "params": { - "form": { - "customerId": "mike" - } - } - }, - "compensation": { - "method": "put", - "path": "/reservations", - "params": { - "form": { - "customerId": "mike" - } - } - } - }, - { - "id": "request-flight", - "type": "rest", - "serviceName": "flight-booking-service", - "transaction": { - "method": "post", - "path": "/bookings", - "params": { - "form": { - "customerId": "mike" - } - } - }, - "compensation": { - "method": "put", - "path": "/bookings", - "params": { - "form": { - "customerId": "mike" - } - } - } - }, - { - "id": "request-payment", - "type": "rest", - "serviceName": "saga-crossapp:payment-service", - "parents": [ - "request-car", - "request-flight", - "request-hotel" - ], - "transaction": { - "method": "post", - "path": "/payments", - "params": { - "form": { - "customerId": "mike" - } - } - }, - "compensation": { - "method": "put", - "path": "/payments", - "params": { - "form": { - "customerId": "mike" - } - } - } - } - ] -} -``` - -The key to the request dependency lies in definition of parents field in the payment request. It means the payment request -is only executed after `request-car` , `request-flight` , and `request-hotel` are completed. -``` - "id": "request-payment", - "type": "rest", - "serviceName": "payment.servicecomb.io:8080", - "parents": [ - "request-car", // request id to car service in the full request json - "request-flight", // request id to flight service in the full request json - "request-hotel" // request id to hotel service in the full request json - ] -``` - -To send the above JSON request to Saga, use [postman](https://www.getpostman.com/postman) with POST request to url `http://:8083/requests` - -Sending the request more than once will trigger compensation due to insufficient account balance in payment-service. - -**Note** transactions and compensations implemented by services must be idempotent. In this demo, we did not enforce that -for simplicity. - -To see all events generated by Saga, visit `http://:8083/events` with browser. diff --git a/saga-demo/dependency-free-transaction-demo/car-rental-service/pom.xml b/saga-demo/dependency-free-transaction-demo/car-rental-service/pom.xml deleted file mode 100644 index d4a3b428c..000000000 --- a/saga-demo/dependency-free-transaction-demo/car-rental-service/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - dependency-free-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - car-rental-service - Saga::Demo::Dependency Free Transaction::Car Rental Service - - - - - io.servicecomb - spring-boot-starter-provider - - - log4j - log4j - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - - diff --git a/saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/java/org/apache/servicecomb/saga/demo/car/rental/CarRentalApplication.java b/saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/java/org/apache/servicecomb/saga/demo/car/rental/CarRentalApplication.java deleted file mode 100644 index d3e0e956b..000000000 --- a/saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/java/org/apache/servicecomb/saga/demo/car/rental/CarRentalApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.car.rental; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -import io.servicecomb.springboot.starter.provider.EnableServiceComb; - -@SpringBootApplication -@EnableServiceComb -public class CarRentalApplication { - - public static void main(String[] args) { - SpringApplication.run(CarRentalApplication.class, args); - } -} diff --git a/saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/java/org/apache/servicecomb/saga/demo/car/rental/CarRentalController.java b/saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/java/org/apache/servicecomb/saga/demo/car/rental/CarRentalController.java deleted file mode 100644 index 4a98141b7..000000000 --- a/saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/java/org/apache/servicecomb/saga/demo/car/rental/CarRentalController.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.car.rental; - -import static java.util.Arrays.asList; -import static javax.ws.rs.core.Response.Status.FORBIDDEN; -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -import java.lang.invoke.MethodHandles; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestMapping; - -import io.servicecomb.provider.rest.common.RestSchema; -import io.servicecomb.swagger.invocation.exception.InvocationException; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -@Controller -@RequestMapping("/") -@RestSchema(schemaId = "car-endpoint") -public class CarRentalController { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private final Set customers = new HashSet<>(asList("mike", "snail")); - private int delay = 60; - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "authenticated user"), - @ApiResponse(code = 403, response = String.class, message = "unauthenticated user") - }) - @RequestMapping(value = "rentals", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity rent(@RequestAttribute String customerId) { - log.info("Received car rental request from customer {}", customerId); - if (!customers.contains(customerId)) { - log.info("No such customer {}", customerId); - throw new InvocationException(FORBIDDEN, "No such customer with id " + customerId); - } - - if ("snail".equals(customerId)) { - try { - log.info("Encountered extremely slow customer {}", customerId); - int timeout = delay; - delay = 0; - TimeUnit.SECONDS.sleep(timeout); - log.info("Finally served the extremely slow customer {}", customerId); - } catch (InterruptedException e) { - return new ResponseEntity<>("Interrupted", INTERNAL_SERVER_ERROR); - } - } - - return ResponseEntity.ok(String.format("{\n" - + " \"body\": \"Car rented with id %s for customer %s\"\n" - + "}", - UUID.randomUUID().toString(), - customerId)); - } - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "authenticated user"), - @ApiResponse(code = 403, response = String.class, message = "unauthenticated user") - }) - @RequestMapping(value = "rentals", method = PUT, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity cancel(@RequestAttribute String customerId) { - if (!customers.contains(customerId)) { - throw new InvocationException(FORBIDDEN, "No such customer with id " + customerId); - } - - return ResponseEntity.ok(String.format("Car rental cancelled with id %s for customer %s", - UUID.randomUUID().toString(), - customerId)); - } -} diff --git a/saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/resources/microservice.yaml b/saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/resources/microservice.yaml deleted file mode 100644 index c60e75aa6..000000000 --- a/saga-demo/dependency-free-transaction-demo/car-rental-service/src/main/resources/microservice.yaml +++ /dev/null @@ -1,30 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -APPLICATION_ID: saga -service_description: - name: car-rental-service - version: 0.0.1 -cse: - service: - registry: - address: http://sc.servicecomb.io:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Consumer: - default: loadbalance diff --git a/saga-demo/dependency-free-transaction-demo/demo-tests/pom.xml b/saga-demo/dependency-free-transaction-demo/demo-tests/pom.xml deleted file mode 100644 index 038a47a6d..000000000 --- a/saga-demo/dependency-free-transaction-demo/demo-tests/pom.xml +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - dependency-free-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - demo-tests - Saga::Demo::Dependency Free Transaction:: Tests - - - - - commons-logging - commons-logging - 1.2 - - - io.rest-assured - rest-assured - test - - - junit - junit - test - - - org.codehaus.groovy - groovy-all - test - - - - - - - io.fabric8 - docker-maven-plugin - - - - servicecomb/service-center:latest - service-center - - - Local listen address - - - 30100 - - - - - - service.center.port:30100 - - - - - postgres - postgres - - - saga - saga - password - - - database system is ready to accept connections - - - 5432 - - - - - - postgres.port:5432 - - - - - car-rental-service:${project.version} - car - - - - - - Started [a-zA-Z]+ in [0-9.]+ seconds - - - 8080 - - - - - - service-center:sc.servicecomb.io - - - car.port:8080 - - - - - flight-booking-service:${project.version} - flight - - - - - - Started [a-zA-Z]+ in [0-9.]+ seconds - - - 8080 - - - - - - service-center:sc.servicecomb.io - - - flight.port:8080 - - - - - hotel-reservation-service:${project.version} - hotel - - - - - - Started [a-zA-Z]+ in [0-9.]+ seconds - - - 8080 - - - - - - service-center:sc.servicecomb.io - - - hotel.port:8080 - - - - - payment-service:${project.version} - payment - - - - - - Started [a-zA-Z]+ in [0-9.]+ seconds - - - 8080 - - - - - - service-center:sc.servicecomb.io - - - payment.port:8080 - - - - - saga-spring:${project.version} - saga - - - - -Dspring.profiles.active=prd,servicecomb - -Dcse.service.registry.address=http://sc.servicecomb.io:30100 - - - - service-center:sc.servicecomb.io - postgres:postgres.servicecomb.io - car:car.servicecomb.io - flight:flight.servicecomb.io - hotel:hotel.servicecomb.io - payment:payment.servicecomb.io - - - Started [a-zA-Z]+ in [0-9.]+ seconds - - - 8080 - - - - - - saga.port:8080 - - - postgres - - - - - - - - start - pre-integration-test - - start - - - - stop - post-integration-test - - stop - - - - - - - - - docker - - - - org.codehaus.gmaven - gmaven-plugin - - - add-default-properties - initialize - - execute - - - - project.properties.setProperty('docker.hostname', 'localhost') - log.info("Docker hostname is " + project.properties['docker.hostname']) - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${maven.failsafe.version} - - - - http://${docker.hostname}:${saga.port} - - - ${jacoco.failsafe.argLine} - - - - - integration-test - verify - - - - - - - - - docker-machine - - - - org.codehaus.gmaven - gmaven-plugin - - - add-dynamic-properties - prepare-package - - execute - - - - def process = "docker-machine ip default".execute() - process.waitFor() - project.properties.setProperty('docker.hostname', process.in.text.trim()) - - log.info("Docker hostname is " + project.properties['docker.hostname']) - - - - - - - - - - - diff --git a/saga-demo/dependency-free-transaction-demo/demo-tests/src/test/java/org/apache/servicecomb/saga/demo/tests/DemoIT.java b/saga-demo/dependency-free-transaction-demo/demo-tests/src/test/java/org/apache/servicecomb/saga/demo/tests/DemoIT.java deleted file mode 100644 index 750b1e4c6..000000000 --- a/saga-demo/dependency-free-transaction-demo/demo-tests/src/test/java/org/apache/servicecomb/saga/demo/tests/DemoIT.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.tests; - -import static io.restassured.RestAssured.given; -import static io.restassured.http.ContentType.TEXT; -import static org.hamcrest.core.Is.is; - -import org.junit.BeforeClass; -import org.junit.Test; - -public class DemoIT { - - private static final String requests = "{\n" - + " \"policy\": \"BackwardRecovery\",\n" - + " \"requests\": [\n" - + " {\n" - + " \"id\": \"request-car\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"car-rental-service\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rentals\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"put\",\n" - + " \"path\": \"/rentals\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " }\n" - + " },\n" - + " {\n" - + " \"id\": \"request-hotel\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"hotel-reservation-service\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/reservations\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"put\",\n" - + " \"path\": \"/reservations\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " }\n" - + " },\n" - + " {\n" - + " \"id\": \"request-flight\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"flight-booking-service\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/bookings\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"put\",\n" - + " \"path\": \"/bookings\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " }\n" - + " },\n" - + " {\n" - + " \"id\": \"request-payment\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"saga-crossapp:payment-service\",\n" - + " \"parents\": [\n" - + " \"request-car\",\n" - + " \"request-flight\",\n" - + " \"request-hotel\"\n" - + " ],\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/payments\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"put\",\n" - + " \"path\": \"/payments\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"customerId\": \"mike\"\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " ]\n" - + "}\n"; - - private static String sagaAddress; - - @BeforeClass - public static void setUp() throws Exception { - sagaAddress = System.getProperty("saga.address"); - } - - @Test - public void ableToSendRequestsToServicesThroughSaga() { - given() - .contentType(TEXT) - .body(requests) - .when() - .post(sagaAddress + "/requests") - .then() - .statusCode(is(200)) - .body(is("success")); - } -} diff --git a/saga-demo/dependency-free-transaction-demo/docker-compose.yaml b/saga-demo/dependency-free-transaction-demo/docker-compose.yaml deleted file mode 100755 index c6282bf5e..000000000 --- a/saga-demo/dependency-free-transaction-demo/docker-compose.yaml +++ /dev/null @@ -1,101 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -version: '2.1' - -services: - service-center: - image: "servicecomb/service-center" - hostname: service-center - ports: - - "30100:30100" - - postgres: - image: "postgres" - hostname: postgres - environment: - - POSTGRES_DB=saga - - POSTGRES_USER=saga - - POSTGRES_PASSWORD=password - ports: - - "5432:5432" - healthcheck: - test: ["CMD-SHELL", "nc -z localhost 5432 &> /dev/null; echo $$?"] - interval: 30s - timeout: 10s - retries: 5 - - car-rental-service: - image: "car-rental-service:0.0.3-SNAPSHOT" - hostname: car - links: - - "service-center:sc.servicecomb.io" - ports: - - "8080" - - flight-booking-service: - image: "flight-booking-service:0.0.3-SNAPSHOT" - hostname: flight - links: - - "service-center:sc.servicecomb.io" - ports: - - "8080" - - hotel-reservation-service: - image: "hotel-reservation-service:0.0.3-SNAPSHOT" - hostname: hotel - links: - - "service-center:sc.servicecomb.io" - ports: - - "8080" - - payment-service: - image: "payment-service:0.0.3-SNAPSHOT" - hostname: payment - links: - - "service-center:sc.servicecomb.io" - ports: - - "8080" - - saga: - image: "saga-spring:0.0.3-SNAPSHOT" - hostname: saga - links: - - "postgres:postgres.servicecomb.io" - - "service-center:sc.servicecomb.io" - - "car-rental-service:car.servicecomb.io" - - "flight-booking-service:flight.servicecomb.io" - - "hotel-reservation-service:hotel.servicecomb.io" - - "payment-service:payment.servicecomb.io" - environment: - - JAVA_OPTS=-Dspring.profiles.active=prd,servicecomb -Dcse.service.registry.address=http://sc.servicecomb.io:30100 - ports: - - "8083:8080" - depends_on: - postgres: - condition: service_healthy - - web: - image: "saga-web:0.0.3-SNAPSHOT" - hostname: web - links: - - "service-center:sc.servicecomb.io" - - "saga:saga.servicecomb.io" - environment: - - JAVA_OPTS=-Dspring.profiles.active=prd,servicecomb -Dcse.service.registry.address=http://sc.servicecomb.io:30100 - ports: - - "8888:8888" diff --git a/saga-demo/dependency-free-transaction-demo/flight-booking-service/pom.xml b/saga-demo/dependency-free-transaction-demo/flight-booking-service/pom.xml deleted file mode 100644 index 3620d3503..000000000 --- a/saga-demo/dependency-free-transaction-demo/flight-booking-service/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - dependency-free-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - flight-booking-service - Saga::Demo::Dependency Free Transaction::Flight Booking Service - - - - - io.servicecomb - spring-boot-starter-provider - - - log4j - log4j - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - - diff --git a/saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/java/org/apache/servicecomb/saga/demo/flight/booking/FlightBookingApplication.java b/saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/java/org/apache/servicecomb/saga/demo/flight/booking/FlightBookingApplication.java deleted file mode 100644 index 5bee98d7e..000000000 --- a/saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/java/org/apache/servicecomb/saga/demo/flight/booking/FlightBookingApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.flight.booking; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -import io.servicecomb.springboot.starter.provider.EnableServiceComb; - -@SpringBootApplication -@EnableServiceComb -public class FlightBookingApplication { - - public static void main(String[] args) { - SpringApplication.run(FlightBookingApplication.class, args); - } -} diff --git a/saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/java/org/apache/servicecomb/saga/demo/flight/booking/FlightBookingController.java b/saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/java/org/apache/servicecomb/saga/demo/flight/booking/FlightBookingController.java deleted file mode 100644 index 37184ace2..000000000 --- a/saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/java/org/apache/servicecomb/saga/demo/flight/booking/FlightBookingController.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.flight.booking; - -import static java.util.Collections.singleton; -import static javax.ws.rs.core.Response.Status.FORBIDDEN; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -import java.util.Set; -import java.util.UUID; - -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestMapping; - -import io.servicecomb.provider.rest.common.RestSchema; -import io.servicecomb.swagger.invocation.exception.InvocationException; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -@Controller -@RequestMapping("/") -@RestSchema(schemaId = "flight-endpoint") -public class FlightBookingController { - private final Set customers = singleton("mike"); - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "authenticated user"), - @ApiResponse(code = 403, response = String.class, message = "unauthenticated user") - }) - @RequestMapping(value = "bookings", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity book(@RequestAttribute String customerId) { - if (!customers.contains(customerId)) { - throw new InvocationException(FORBIDDEN, "No such customer with id " + customerId); - } - - return ResponseEntity.ok(String.format("{\n" - + " \"body\": \"Flight booked with id %s for customer %s\"\n" - + "}", - UUID.randomUUID().toString(), - customerId)); - } - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "authenticated user"), - @ApiResponse(code = 403, response = String.class, message = "unauthenticated user") - }) - @RequestMapping(value = "bookings", method = PUT, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity cancel(@RequestAttribute String customerId) { - if (!customers.contains(customerId)) { - throw new InvocationException(FORBIDDEN, "No such customer with id " + customerId); - } - - return ResponseEntity.ok(String.format("Flight booking cancelled with id %s for customer %s", - UUID.randomUUID().toString(), - customerId)); - } -} diff --git a/saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/resources/microservice.yaml b/saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/resources/microservice.yaml deleted file mode 100644 index fe96db73a..000000000 --- a/saga-demo/dependency-free-transaction-demo/flight-booking-service/src/main/resources/microservice.yaml +++ /dev/null @@ -1,30 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -APPLICATION_ID: saga -service_description: - name: flight-booking-service - version: 0.0.1 -cse: - service: - registry: - address: http://sc.servicecomb.io:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Consumer: - default: loadbalance diff --git a/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/pom.xml b/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/pom.xml deleted file mode 100644 index dd8ad4b36..000000000 --- a/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - dependency-free-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - hotel-reservation-service - Saga::Demo::Dependency Free Transaction::Hotel Reservation Service - - - - - io.servicecomb - spring-boot-starter-provider - - - log4j - log4j - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - - diff --git a/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/java/org/apache/servicecomb/saga/demo/hotel/reservation/HotelReservationApplication.java b/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/java/org/apache/servicecomb/saga/demo/hotel/reservation/HotelReservationApplication.java deleted file mode 100644 index b6d3c01dc..000000000 --- a/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/java/org/apache/servicecomb/saga/demo/hotel/reservation/HotelReservationApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.hotel.reservation; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -import io.servicecomb.springboot.starter.provider.EnableServiceComb; - -@SpringBootApplication -@EnableServiceComb -public class HotelReservationApplication { - - public static void main(String[] args) { - SpringApplication.run(HotelReservationApplication.class, args); - } -} diff --git a/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/java/org/apache/servicecomb/saga/demo/hotel/reservation/HotelReservationController.java b/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/java/org/apache/servicecomb/saga/demo/hotel/reservation/HotelReservationController.java deleted file mode 100644 index dfe00d879..000000000 --- a/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/java/org/apache/servicecomb/saga/demo/hotel/reservation/HotelReservationController.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.hotel.reservation; - -import static java.util.Collections.singleton; -import static javax.ws.rs.core.Response.Status.FORBIDDEN; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -import java.util.Set; -import java.util.UUID; - -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestMapping; - -import io.servicecomb.provider.rest.common.RestSchema; -import io.servicecomb.swagger.invocation.exception.InvocationException; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -@Controller -@RequestMapping("/") -@RestSchema(schemaId = "hotel-endpoint") -public class HotelReservationController { - - private final Set customers = singleton("mike"); - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "authenticated user"), - @ApiResponse(code = 403, response = String.class, message = "unauthenticated user") - }) - @RequestMapping(value = "reservations", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity reserve(@RequestAttribute String customerId) { - if (!customers.contains(customerId)) { - throw new InvocationException(FORBIDDEN, "No such customer with id " + customerId); - } - - return ResponseEntity.ok(String.format("{\n" - + " \"body\": \"Hotel reserved with id %s for customer %s\"\n" - + "}", - UUID.randomUUID().toString(), - customerId)); - } - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "authenticated user"), - @ApiResponse(code = 403, response = String.class, message = "unauthenticated user") - }) - @RequestMapping(value = "reservations", method = PUT, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity cancel(@RequestAttribute String customerId) { - if (!customers.contains(customerId)) { - throw new InvocationException(FORBIDDEN, "No such customer with id " + customerId); - } - - return ResponseEntity.ok(String.format("Hotel reservation cancelled with id %s for customer %s", - UUID.randomUUID().toString(), - customerId)); - } -} diff --git a/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/resources/microservice.yaml b/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/resources/microservice.yaml deleted file mode 100644 index ea01a2a32..000000000 --- a/saga-demo/dependency-free-transaction-demo/hotel-reservation-service/src/main/resources/microservice.yaml +++ /dev/null @@ -1,30 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -APPLICATION_ID: saga -service_description: - name: hotel-reservation-service - version: 0.0.1 -cse: - service: - registry: - address: http://sc.servicecomb.io:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Consumer: - default: loadbalance diff --git a/saga-demo/dependency-free-transaction-demo/payment-service/pom.xml b/saga-demo/dependency-free-transaction-demo/payment-service/pom.xml deleted file mode 100644 index 045f324ba..000000000 --- a/saga-demo/dependency-free-transaction-demo/payment-service/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - dependency-free-transaction-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - payment-service - Saga::Demo::Dependency Free Transaction::Payment Service - - - - - io.servicecomb - spring-boot-starter-provider - - - log4j - log4j - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - - diff --git a/saga-demo/dependency-free-transaction-demo/payment-service/src/main/java/org/apache/servicecomb/saga/demo/payment/PaymentApplication.java b/saga-demo/dependency-free-transaction-demo/payment-service/src/main/java/org/apache/servicecomb/saga/demo/payment/PaymentApplication.java deleted file mode 100644 index 4395c22c7..000000000 --- a/saga-demo/dependency-free-transaction-demo/payment-service/src/main/java/org/apache/servicecomb/saga/demo/payment/PaymentApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.payment; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -import io.servicecomb.springboot.starter.provider.EnableServiceComb; - -@SpringBootApplication -@EnableServiceComb -public class PaymentApplication { - - public static void main(String[] args) { - SpringApplication.run(PaymentApplication.class, args); - } -} diff --git a/saga-demo/dependency-free-transaction-demo/payment-service/src/main/java/org/apache/servicecomb/saga/demo/payment/PaymentController.java b/saga-demo/dependency-free-transaction-demo/payment-service/src/main/java/org/apache/servicecomb/saga/demo/payment/PaymentController.java deleted file mode 100644 index cf1e77498..000000000 --- a/saga-demo/dependency-free-transaction-demo/payment-service/src/main/java/org/apache/servicecomb/saga/demo/payment/PaymentController.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.demo.payment; - -import static javax.ws.rs.core.Response.Status.BAD_REQUEST; -import static javax.ws.rs.core.Response.Status.FORBIDDEN; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestMapping; - -import io.servicecomb.provider.rest.common.RestSchema; -import io.servicecomb.swagger.invocation.exception.InvocationException; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -@Controller -@RequestMapping("/") -@RestSchema(schemaId = "payment-endpoint") -public class PaymentController { - private int balance = 1000; - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "authenticated user"), - @ApiResponse(code = 403, response = String.class, message = "unauthenticated user"), - @ApiResponse(code = 400, response = String.class, message = "insufficient account balance") - }) - @RequestMapping(value = "payments", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity pay(@RequestAttribute String customerId) { - if ("anonymous".equals(customerId)) { - throw new InvocationException(FORBIDDEN, "No such customer with id " + customerId); - } - - if (balance < 800) { - throw new InvocationException(BAD_REQUEST, "Not enough balance in account of customer " + customerId); - } - - balance -= 800; - return ResponseEntity.ok(String.format("{\n" - + " \"body\": \"Payment made for customer %s and remaining balance is %d\"\n" - + "}", - customerId, - balance)); - } - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "authenticated user"), - @ApiResponse(code = 403, response = String.class, message = "unauthenticated user") - }) - @RequestMapping(value = "payments", method = PUT, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity refund(@RequestAttribute String customerId) { - if ("anonymous".equals(customerId)) { - throw new InvocationException(FORBIDDEN, "No such customer with id " + customerId); - } - - balance += 800; - return ResponseEntity.ok(String.format("Payment refunded for customer %s and remaining balance is %d", - customerId, - balance)); - } -} diff --git a/saga-demo/dependency-free-transaction-demo/payment-service/src/main/resources/microservice.yaml b/saga-demo/dependency-free-transaction-demo/payment-service/src/main/resources/microservice.yaml deleted file mode 100644 index e520f9af0..000000000 --- a/saga-demo/dependency-free-transaction-demo/payment-service/src/main/resources/microservice.yaml +++ /dev/null @@ -1,32 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -APPLICATION_ID: saga-crossapp -service_description: - name: payment-service - version: 0.0.1 - properties: - allowCrossApp: true -cse: - service: - registry: - address: http://sc.servicecomb.io:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Consumer: - default: loadbalance diff --git a/saga-demo/dependency-free-transaction-demo/pom.xml b/saga-demo/dependency-free-transaction-demo/pom.xml deleted file mode 100644 index 4765900fe..000000000 --- a/saga-demo/dependency-free-transaction-demo/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - saga-demo - org.apache.servicecomb.saga.demo - 0.0.3-SNAPSHOT - - 4.0.0 - - dependency-free-transaction-demo - Saga::Demo::Dependency Free Transaction - pom - - - - - org.apache.commons - commons-lang3 - 3.6 - - - io.servicecomb - spring-boot-starter-provider - ${java.chassis.version} - - - com.google.code.findbugs - annotations - - - - - io.servicecomb - java-chassis-dependencies - ${java.chassis.version} - pom - import - - - - - - car-rental-service - flight-booking-service - hotel-reservation-service - payment-service - demo-tests - - - diff --git a/saga-demo/pom.xml b/saga-demo/pom.xml index dfdef267a..43f417f44 100644 --- a/saga-demo/pom.xml +++ b/saga-demo/pom.xml @@ -30,8 +30,6 @@ pom - dependency-free-transaction-demo - conditional-transaction-demo pack-demo diff --git a/saga-discovery/pom.xml b/saga-discovery/pom.xml deleted file mode 100644 index 676db6180..000000000 --- a/saga-discovery/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - saga - org.apache.servicecomb.saga - 0.0.3-SNAPSHOT - - 4.0.0 - - org.apache.servicecomb.saga.discovery - saga-discovery - Saga::Discovery - - pom - - saga-discovery-servicecenter - - - - diff --git a/saga-discovery/saga-discovery-servicecenter/pom.xml b/saga-discovery/saga-discovery-servicecenter/pom.xml deleted file mode 100644 index 86787148c..000000000 --- a/saga-discovery/saga-discovery-servicecenter/pom.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - saga-discovery - org.apache.servicecomb.saga.discovery - 0.0.3-SNAPSHOT - - 4.0.0 - - saga-discovery-servicecenter - Saga::Discovery::ServiceCenter - - - - - org.springframework.boot - spring-boot-starter-test - ${spring.boot.version} - - - org.json - json - - - test - - - io.servicecomb - spring-boot-starter-provider - ${java.chassis.version} - - - com.google.code.findbugs - annotations - - - - - io.servicecomb - java-chassis-dependencies - ${java.chassis.version} - pom - import - - - - - - - org.apache.servicecomb.saga - saga-core - - - org.apache.servicecomb.saga.transports - transport-httpclient-spring - - - org.apache.servicecomb.saga.transports - transport-resttemplate - - - io.servicecomb - spring-boot-starter-provider - - - log4j - log4j - - - - - org.springframework.boot - spring-boot-starter - - - ch.qos.logback - * - - - - - - org.springframework.boot - spring-boot-starter-web - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.hibernate - hibernate-validator - 5.2.4.Final - test - - - junit - junit - - - com.github.seanyinx - unit-scaffolding - - - diff --git a/saga-discovery/saga-discovery-servicecenter/src/main/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryConfig.java b/saga-discovery/saga-discovery-servicecenter/src/main/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryConfig.java deleted file mode 100644 index 11110eff8..000000000 --- a/saga-discovery/saga-discovery-servicecenter/src/main/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryConfig.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.discovery.service.center; - -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -import io.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.saga.transports.HttpClientTransportConfig; -import org.apache.servicecomb.saga.transports.RestTransport; -import org.apache.servicecomb.saga.transports.resttemplate.RestTemplateTransport; -import io.servicecomb.springboot.starter.provider.EnableServiceComb; - -@EnableServiceComb -@Profile("servicecomb") -@Configuration -@AutoConfigureBefore(HttpClientTransportConfig.class) -public class ServiceCenterDiscoveryConfig { - - static final String PROTOCOL = "cse://"; - - @Bean - RestTransport restTransport() { - return new RestTemplateTransport(RestTemplateBuilder.create(), PROTOCOL); - } -} diff --git a/saga-discovery/saga-discovery-servicecenter/src/main/resources/META-INF/spring.factories b/saga-discovery/saga-discovery-servicecenter/src/main/resources/META-INF/spring.factories deleted file mode 100644 index b199c22a6..000000000 --- a/saga-discovery/saga-discovery-servicecenter/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,18 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.apache.servicecomb.saga.discovery.service.center.ServiceCenterDiscoveryConfig diff --git a/saga-discovery/saga-discovery-servicecenter/src/main/resources/microservice.yaml b/saga-discovery/saga-discovery-servicecenter/src/main/resources/microservice.yaml deleted file mode 100644 index c183fc965..000000000 --- a/saga-discovery/saga-discovery-servicecenter/src/main/resources/microservice.yaml +++ /dev/null @@ -1,30 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -APPLICATION_ID: saga -service_description: - name: saga-service - version: 0.0.1 -cse: - service: - registry: - address: http://sc.servicecomb.io:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Consumer: - default: loadbalance diff --git a/saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/DummyController.java b/saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/DummyController.java deleted file mode 100644 index 710806d17..000000000 --- a/saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/DummyController.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.discovery.service.center; - -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.GET; -import static org.springframework.web.bind.annotation.RequestMethod.POST; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import io.servicecomb.provider.rest.common.RestSchema; - -@Controller -@RequestMapping("/rest") -@RestSchema(schemaId = "dummy-rest-endpoint") -public class DummyController { - - @RequestMapping(value = "/usableResource", method = GET) - public ResponseEntity getUseableResource( - @RequestParam(name = "foo") String foo, - @RequestParam(name = "hello") String who) { - - return ResponseEntity.ok("foo " + foo + ", hello " + who); - } - - @RequestMapping(value = "/usableResource", method = PUT) - public ResponseEntity putUseableResource(@RequestParam(name = "foo") String foo, @RequestBody String json) { - return ResponseEntity.ok("foo " + foo + ", hello world" + json); - } - - @RequestMapping(value = "/faultyResource", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE) - public ResponseEntity postFaultyResource(@RequestParam(name = "foo") String foo, @RequestAttribute(name = "hello") String hello) { - throw new RuntimeException("no such resource"); - } -} diff --git a/saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryApplication.java b/saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryApplication.java deleted file mode 100644 index 027b44187..000000000 --- a/saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.discovery.service.center; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -import io.servicecomb.springboot.starter.provider.EnableServiceComb; - -@SpringBootApplication -@EnableServiceComb -public class ServiceCenterDiscoveryApplication { - - public static void main(String[] args) { - SpringApplication.run(ServiceCenterDiscoveryApplication.class, args); - } -} diff --git a/saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryRestTransportTest.java b/saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryRestTransportTest.java deleted file mode 100644 index 6bfa7ae77..000000000 --- a/saga-discovery/saga-discovery-servicecenter/src/test/java/org/apache/servicecomb/saga/discovery/service/center/ServiceCenterDiscoveryRestTransportTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.discovery.service.center; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static io.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - -import java.net.URL; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.transports.RestTransport; -import org.apache.servicecomb.saga.transports.resttemplate.RestTemplateTransport; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import io.servicecomb.provider.springmvc.reference.RestTemplateBuilder; - -import org.apache.servicecomb.saga.core.TransportFailedException; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = ServiceCenterDiscoveryApplication.class, webEnvironment = RANDOM_PORT) -public class ServiceCenterDiscoveryRestTransportTest { - - private static final String usableResource = "/rest/usableResource"; - private static final String faultyResource = "/rest/faultyResource"; - private static final String usableResponse = "foo bar, hello world"; - private static final String json = "{\"hello\", \"world\"}"; - - private final RestTransport transport = new RestTemplateTransport(RestTemplateBuilder.create(), ServiceCenterDiscoveryConfig.PROTOCOL); - private final String serviceName = "saga-service"; - - @BeforeClass - public static void setUpClass() throws Exception { - setUpLocalRegistry(); - } - - private static void setUpLocalRegistry() { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - URL resource = loader.getResource("registry.yaml"); - System.setProperty(LOCAL_REGISTRY_FILE_KEY, resource.getPath()); - } - - @Test - public void sendsGetRequestToDiscoveredService() { - Map> requests = singletonMap("query", map("foo", "bar", "hello", "world")); - SagaResponse response = transport.with(serviceName, usableResource, "get", requests); - - assertThat(response.succeeded(), is(true)); - assertThat(response.body(), containsString(usableResponse)); - } - - @Test - public void putsRequestToDiscoveredService() { - Map> requests = new HashMap<>(); - requests.put("query", singletonMap("foo", "bar")); - requests.put("json", singletonMap("body", json)); - - SagaResponse response = transport.with(serviceName, usableResource, "PUT", requests); - - assertThat(response.succeeded(), is(true)); - assertThat(response.body(), containsString(usableResponse + json)); - } - - @Test - public void blowsUpWhenRemoteResponseIsNot2XX() { - Map> requests = new HashMap<>(); - requests.put("query", singletonMap("foo", "bar")); - requests.put("form", map("hello", "world")); - - try { - transport.with(serviceName, faultyResource, "POST", requests); - expectFailing(TransportFailedException.class); - } catch (TransportFailedException e) { - assertThat(e.getMessage(), containsString("The remote service " + serviceName + " failed to serve")); - } - } - - @Test - public void blowsUpWhenRemoteIsNotReachable() { - try { - transport.with("unknown-service", faultyResource, "DELETE", emptyMap()); - expectFailing(TransportFailedException.class); - } catch (TransportFailedException e) { - assertThat(e.getMessage(), containsString("The remote service unknown-service failed to serve")); - } - } - - @Test - public void blowsUpWhenMethodIsUnknown() { - try { - transport.with(serviceName, usableResource, "Blah", emptyMap()); - expectFailing(TransportFailedException.class); - } catch (TransportFailedException e) { - assertThat(e.getCause().getMessage(), is("No such method Blah")); - } - } - - private Map map(String... pairs) { - return new LinkedHashMap() {{ - for (int i = 0; i < pairs.length; i += 2) { - put(pairs[i], pairs[i + 1]); - } - }}; - } -} diff --git a/saga-discovery/saga-discovery-servicecenter/src/test/resources/log4j2-test.xml b/saga-discovery/saga-discovery-servicecenter/src/test/resources/log4j2-test.xml deleted file mode 100644 index 58924c686..000000000 --- a/saga-discovery/saga-discovery-servicecenter/src/test/resources/log4j2-test.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/saga-discovery/saga-discovery-servicecenter/src/test/resources/registry.yaml b/saga-discovery/saga-discovery-servicecenter/src/test/resources/registry.yaml deleted file mode 100644 index 82752b441..000000000 --- a/saga-discovery/saga-discovery-servicecenter/src/test/resources/registry.yaml +++ /dev/null @@ -1,23 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -saga-service: - - id: "001" - version: "0.0.1" - appid: saga - instances: - - endpoints: - - rest://127.0.0.1:8080?sslEnabled=false diff --git a/saga-format/pom.xml b/saga-format/pom.xml deleted file mode 100644 index a6c045785..000000000 --- a/saga-format/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - saga - org.apache.servicecomb.saga - 0.0.3-SNAPSHOT - - 4.0.0 - - saga-format - Saga::Format - - - - org.apache.servicecomb.saga - saga-core - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - io.kamon - kamon-core_2.12 - - - io.kamon - kamon-annotation_2.12 - - - - org.hamcrest - hamcrest-all - - - org.mockito - mockito-core - - - junit - junit - test - - - com.github.seanyinx - unit-scaffolding - test - - - - diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/core/FailedSagaRequestContext.java b/saga-format/src/main/java/org/apache/servicecomb/saga/core/FailedSagaRequestContext.java deleted file mode 100644 index 92d603927..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/core/FailedSagaRequestContext.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import org.apache.servicecomb.saga.format.JsonFailedSagaResponse; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.apache.servicecomb.saga.format.JsonSagaRequest; - -public class FailedSagaRequestContext extends SagaRequestContext { - - private final JsonSagaRequest request; - - public FailedSagaRequestContext( - @JsonProperty("request") JsonSagaRequest request, - @JsonProperty("response") JsonFailedSagaResponse response) { - super(request, response); - this.request = request; - } - - public JsonSagaRequest request() { - return request; - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/core/JacksonToJsonFormat.java b/saga-format/src/main/java/org/apache/servicecomb/saga/core/JacksonToJsonFormat.java deleted file mode 100644 index c00ce4a36..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/core/JacksonToJsonFormat.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY; -import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class JacksonToJsonFormat implements ToJsonFormat { - - - private final ObjectMapper objectMapper = new ObjectMapper(); - - public JacksonToJsonFormat() { - objectMapper.setVisibility( - objectMapper.getSerializationConfig() - .getDefaultVisibilityChecker() - .withFieldVisibility(ANY) - .withGetterVisibility(NONE) - .withSetterVisibility(NONE) - .withCreatorVisibility(NONE)); - - } - - @Segment(name = "toJson", category = "application", library = "kamon") - @Override - public String toJson(SagaRequest request) { - try { - return objectMapper.writeValueAsString(request); - } catch (JsonProcessingException e) { - throw new SagaException("Failed to serialize request to JSON: " + request, e); - } - } - - @Segment(name = "toJson", category = "application", library = "kamon") - @Override - public String toJson(SagaRequest request, SagaResponse response) { - try { - return objectMapper.writeValueAsString(new SagaRequestContext(request, response)); - } catch (JsonProcessingException e) { - throw new SagaException("Failed to serialize request & response to JSON: " + request + ", " + response, e); - } - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/core/SagaRequestContext.java b/saga-format/src/main/java/org/apache/servicecomb/saga/core/SagaRequestContext.java deleted file mode 100644 index 2e3761721..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/core/SagaRequestContext.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -public class SagaRequestContext { - - private final SagaRequest request; - private final SagaResponse response; - - SagaRequestContext(SagaRequest request, SagaResponse response) { - this.request = request; - this.response = response; - } - - public SagaRequest request() { - return request; - } - - public SagaResponse response() { - return response; - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/core/SuccessfulSagaRequestContext.java b/saga-format/src/main/java/org/apache/servicecomb/saga/core/SuccessfulSagaRequestContext.java deleted file mode 100644 index f794a91ec..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/core/SuccessfulSagaRequestContext.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.core; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.apache.servicecomb.saga.format.JsonSagaRequest; -import org.apache.servicecomb.saga.format.JsonSuccessfulSagaResponse; - -public class SuccessfulSagaRequestContext extends SagaRequestContext { - - private final JsonSagaRequest request; - - @JsonCreator - public SuccessfulSagaRequestContext( - @JsonProperty("request") JsonSagaRequest request, - @JsonProperty("response") JsonSuccessfulSagaResponse response) { - super(request, response); - this.request = request; - } - - public JsonSagaRequest request() { - return request; - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/ChildrenExtractor.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/ChildrenExtractor.java deleted file mode 100644 index cfd3b1c43..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/ChildrenExtractor.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -import org.apache.servicecomb.saga.core.SagaException; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; - -public class ChildrenExtractor implements FromJsonFormat> { - - private static final String SAGA_CHILDREN = "sagaChildren"; - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Override - public Set fromJson(String json) { - try { - return childrenOf(objectMapper.readValue(json, ObjectNode.class)); - } catch (IOException e) { - throw new SagaException("Failed to deserialize json " + json, e); - } - } - - private Set childrenOf(ObjectNode value) { - Set children = new HashSet<>(); - - if (value.has(SAGA_CHILDREN)) { - value.get(SAGA_CHILDREN) - .forEach(node -> children.add(node.textValue())); - } - - return children; - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonFallback.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonFallback.java deleted file mode 100644 index 443ba66ca..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonFallback.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import org.apache.servicecomb.saga.core.Fallback; -import org.apache.servicecomb.saga.core.Operation; -import org.apache.servicecomb.saga.transports.TransportFactory; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonSubTypes.Type; -import com.fasterxml.jackson.annotation.JsonTypeInfo; - -import org.apache.servicecomb.saga.format.JacksonFallback.NopJacksonFallback; - -@JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, - include = JsonTypeInfo.As.PROPERTY, - visible = true, - property = "type") -@JsonSubTypes({ - @Type(value = JacksonRestFallback.class, name = Operation.TYPE_REST), - @Type(value = NopJacksonFallback.class, name = Operation.TYPE_NOP) -}) -public interface JacksonFallback extends Fallback, TransportAware { - - JacksonFallback NOP_TRANSPORT_AWARE_FALLBACK = new NopJacksonFallback(TYPE_NOP); - - class NopJacksonFallback implements JacksonFallback { - - private final String type; - - @JsonCreator - public NopJacksonFallback(@JsonProperty("type") String type) { - this.type = type; - } - - @Override - public String type() { - return type; - } - - @Override - public Operation with(TransportFactory transport) { - return this; - } - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonFromJsonFormat.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonFromJsonFormat.java deleted file mode 100644 index c26a82f28..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonFromJsonFormat.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import java.io.IOException; - -import org.apache.servicecomb.saga.transports.TransportFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.apache.servicecomb.saga.core.SagaDefinition; -import org.apache.servicecomb.saga.core.SagaException; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class JacksonFromJsonFormat implements FromJsonFormat { - - private final ObjectMapper objectMapper = new ObjectMapper(); - private final TransportFactory transportFactory; - - public JacksonFromJsonFormat(TransportFactory transportFactory) { - this.transportFactory = transportFactory; - } - - @Segment(name = "fromJson", category = "application", library = "kamon") - @Override - public SagaDefinition fromJson(String requestJson) { - try { - JsonSagaDefinition definition = objectMapper.readValue(requestJson, JsonSagaDefinition.class); - - for (JsonSagaRequest request : definition.requests()) { - request.with(transportFactory); - } - - return definition; - } catch (IOException e) { - throw new SagaException("Failed to interpret JSON " + requestJson, e); - } - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestCompensation.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestCompensation.java deleted file mode 100644 index 1837563ed..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestCompensation.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import java.util.Map; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.apache.servicecomb.saga.core.Compensation; - -public class JacksonRestCompensation extends JacksonRestOperation implements Compensation { - - private final int retries; - - public JacksonRestCompensation( - String path, - String method, - Map> params) { - this(DEFAULT_RETRIES, path, method, params); - } - - @JsonCreator - public JacksonRestCompensation( - @JsonProperty("retries") int retries, - @JsonProperty("path") String path, - @JsonProperty("method") String method, - @JsonProperty("params") Map> params) { - super(path, method, params); - this.retries = retries <= 0? DEFAULT_RETRIES : retries; - } - - @Override - public int retries() { - return retries; - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestFallback.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestFallback.java deleted file mode 100644 index 35c54fe34..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestFallback.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import java.util.Map; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -class JacksonRestFallback extends JacksonRestOperation implements JacksonFallback { - - private final String type; - - @JsonCreator - public JacksonRestFallback( - @JsonProperty("type") String type, - @JsonProperty("path") String path, - @JsonProperty("method") String method, - @JsonProperty("params") Map> params) { - super(path, method, params); - this.type = type; - } - - @Override - public String type() { - return type; - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestOperation.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestOperation.java deleted file mode 100644 index 4d4245174..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestOperation.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.saga.transports.TransportFactory; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import org.apache.servicecomb.saga.core.RestOperation; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.transports.RestTransport; - -class JacksonRestOperation extends RestOperation implements TransportAware { - - @JsonIgnore - private RestTransport transport; - - JacksonRestOperation(String path, String method, Map> params) { - super(path, method, params); - } - - @Override - public JacksonRestOperation with(TransportFactory transport) { - this.transport = transport.restTransport(); - return this; - } - - @Override - public SagaResponse send(String address) { - return transport.with(address, path(), method(), params()); - } - - @Override - public SagaResponse send(String address, SagaResponse response) { - Map> updated = new HashMap<>(params()); - updated.computeIfAbsent("form", (key) -> new HashMap<>()).put("response", response.body()); - - return transport.with( - address, - path(), - method(), - updated); - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestTransaction.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestTransaction.java deleted file mode 100644 index 4ea6d8c9f..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonRestTransaction.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import java.util.Map; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.apache.servicecomb.saga.core.Transaction; - -public class JacksonRestTransaction extends JacksonRestOperation implements Transaction { - - @JsonCreator - public JacksonRestTransaction( - @JsonProperty("path") String path, - @JsonProperty("method") String method, - @JsonProperty("params") Map> params) { - super(path, method, params); - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonSagaEventFormat.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonSagaEventFormat.java deleted file mode 100644 index 1b416aaf6..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JacksonSagaEventFormat.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiFunction; - -import org.apache.servicecomb.saga.core.FailedSagaRequestContext; -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.SagaEvent; -import org.apache.servicecomb.saga.core.SagaException; -import org.apache.servicecomb.saga.core.SagaStartedEvent; -import org.apache.servicecomb.saga.core.SuccessfulSagaRequestContext; -import org.apache.servicecomb.saga.core.TransactionAbortedEvent; -import org.apache.servicecomb.saga.core.TransactionCompensatedEvent; -import org.apache.servicecomb.saga.core.TransactionStartedEvent; -import org.apache.servicecomb.saga.transports.TransportFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.apache.servicecomb.saga.core.SagaEndedEvent; -import org.apache.servicecomb.saga.core.TransactionEndedEvent; - -public class JacksonSagaEventFormat implements SagaEventFormat { - private final Map> eventFactories = new HashMap>() {{ - put(SagaStartedEvent.class.getSimpleName(), (sagaId, json) -> sagaStartedEvent(sagaId, json)); - put(TransactionStartedEvent.class.getSimpleName(), (sagaId, json) -> transactionStartedEvent(sagaId, json)); - put(TransactionEndedEvent.class.getSimpleName(), (sagaId, json) -> transactionEndedEvent(sagaId, json)); - put(TransactionAbortedEvent.class.getSimpleName(), (sagaId, json) -> transactionAbortedEvent(sagaId, json)); - put(TransactionCompensatedEvent.class.getSimpleName(), (sagaId, json) -> compensationEndedEvent(sagaId, json)); - put(SagaEndedEvent.class.getSimpleName(), (sagaId, json) -> sagaEndedEvent(sagaId)); - }}; - - private final ObjectMapper objectMapper = new ObjectMapper(); - private final TransportFactory transportFactory; - - public JacksonSagaEventFormat(TransportFactory transportFactory) { - this.transportFactory = transportFactory; - } - - @Override - public SagaEvent toSagaEvent(String sagaId, String eventType, String contentJson) { - return eventFactories.get(eventType).apply(sagaId, contentJson); - } - - private SagaEvent sagaStartedEvent(String sagaId, String json) { - return new SagaStartedEvent( - sagaId, - json, - NoOpSagaRequest.SAGA_START_REQUEST); - } - - private SagaEvent transactionStartedEvent(String sagaId, String json) { - try { - return new TransactionStartedEvent(sagaId, objectMapper.readValue(json, JsonSagaRequest.class).with(transportFactory)); - } catch (IOException e) { - throw new SagaException(cause(sagaId, json), e); - } - } - - private SagaEvent transactionEndedEvent(String sagaId, String json) { - try { - SuccessfulSagaRequestContext context = objectMapper.readValue(json, SuccessfulSagaRequestContext.class); - return new TransactionEndedEvent(sagaId, context.request().with(transportFactory), context.response()); - } catch (IOException e) { - throw new SagaException(cause(sagaId, json), e); - } - } - - private SagaEvent transactionAbortedEvent(String sagaId, String json) { - try { - FailedSagaRequestContext context = objectMapper.readValue(json, FailedSagaRequestContext.class); - return new TransactionAbortedEvent(sagaId, context.request().with(transportFactory), context.response()); - } catch (IOException e) { - throw new SagaException(cause(sagaId, json), e); - } - } - - private SagaEvent compensationEndedEvent(String sagaId, String json) { - try { - SuccessfulSagaRequestContext context = objectMapper.readValue(json, SuccessfulSagaRequestContext.class); - return new TransactionCompensatedEvent(sagaId, context.request().with(transportFactory), context.response()); - } catch (IOException e) { - throw new SagaException(cause(sagaId, json), e); - } - } - - private SagaEvent sagaEndedEvent(String sagaId) { - return new SagaEndedEvent( - sagaId, - NoOpSagaRequest.SAGA_END_REQUEST); - } - - private String cause(String sagaId, String json) { - return "Failed to deserialize saga event of sage id: " + sagaId + " from json: " + json; - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonFailedSagaResponse.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonFailedSagaResponse.java deleted file mode 100644 index 16ada6ef6..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonFailedSagaResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.apache.servicecomb.saga.core.FailedSagaResponse; - -public class JsonFailedSagaResponse extends FailedSagaResponse { - - public JsonFailedSagaResponse(@JsonProperty("body") String body) { - super(body); - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonRestSagaRequest.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonRestSagaRequest.java deleted file mode 100644 index 9660eb4e3..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonRestSagaRequest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import static org.apache.servicecomb.saga.format.JacksonFallback.NOP_TRANSPORT_AWARE_FALLBACK; - -import org.apache.servicecomb.saga.core.SagaRequestImpl; -import org.apache.servicecomb.saga.transports.TransportFactory; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.apache.servicecomb.saga.core.Operation; - -public class JsonRestSagaRequest extends SagaRequestImpl implements JsonSagaRequest { - - private final JacksonRestTransaction transaction; - private final JacksonRestCompensation compensation; - private final JacksonFallback fallback; - - @JsonCreator - public JsonRestSagaRequest( - @JsonProperty("id") String id, - @JsonProperty("serviceName") String serviceName, - @JsonProperty("type") String type, - @JsonProperty("transaction") JacksonRestTransaction transaction, - @JsonProperty("compensation") JacksonRestCompensation compensation, - @JsonProperty("fallback") JacksonFallback fallback, - @JsonProperty("parents") String[] parents, - @JsonProperty("failRetryDelayMilliseconds") int failRetryDelayMilliseconds) { - - super(id, serviceName, type, transaction, compensation, - fallback == null ? NOP_TRANSPORT_AWARE_FALLBACK : fallback, - parents, failRetryDelayMilliseconds); - - checkNull(transaction, "transaction"); - checkNull(compensation, "compensation"); - - this.transaction = transaction; - this.compensation = compensation; - this.fallback = fallback == null ? NOP_TRANSPORT_AWARE_FALLBACK : fallback; - } - - @Override - public JsonSagaRequest with(TransportFactory transportFactory) { - transaction.with(transportFactory); - compensation.with(transportFactory); - fallback.with(transportFactory); - return this; - } - - private void checkNull(Operation operation, String operationName) { - if (operation == null) { - throw new IllegalArgumentException("Invalid request with NO " + operationName + " specified"); - } - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSagaDefinition.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSagaDefinition.java deleted file mode 100644 index 5293a130c..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSagaDefinition.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.saga.core.ForwardRecovery; -import org.apache.servicecomb.saga.core.RecoveryPolicy; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.apache.servicecomb.saga.core.BackwardRecovery; -import org.apache.servicecomb.saga.core.SagaDefinition; - -class JsonSagaDefinition implements SagaDefinition { - - static final RecoveryPolicy backwardRecovery = new BackwardRecovery(); - - private static final Map policies = new HashMap(){{ - put(RecoveryPolicy.SAGA_BACKWARD_RECOVERY_POLICY, backwardRecovery); - put(RecoveryPolicy.SAGA_FORWARD_RECOVERY_POLICY, new ForwardRecovery()); - }}; - - private final JsonSagaRequest[] requests; - private final RecoveryPolicy policy; - - public JsonSagaDefinition( - @JsonProperty("policy") String policy, - @JsonProperty("requests") JsonSagaRequest[] requests) { - - this.requests = requests; - this.policy = policies.getOrDefault(policy, backwardRecovery); - } - - @Override - public RecoveryPolicy policy() { - return policy; - } - - @Override - public JsonSagaRequest[] requests() { - return requests; - } -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSagaRequest.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSagaRequest.java deleted file mode 100644 index 45d398109..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSagaRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import org.apache.servicecomb.saga.core.Operation; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.transports.TransportFactory; - -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonSubTypes.Type; -import com.fasterxml.jackson.annotation.JsonTypeInfo; - -@JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, - include = JsonTypeInfo.As.PROPERTY, - visible = true, - property = "type") -@JsonSubTypes({ - @Type(value = JsonRestSagaRequest.class, name = Operation.TYPE_REST) -}) -public interface JsonSagaRequest extends SagaRequest { - - JsonSagaRequest with(TransportFactory transportFactory); -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSuccessfulSagaResponse.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSuccessfulSagaResponse.java deleted file mode 100644 index 273fc3d6c..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/JsonSuccessfulSagaResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.apache.servicecomb.saga.core.SuccessfulSagaResponse; - -public class JsonSuccessfulSagaResponse extends SuccessfulSagaResponse { - - public JsonSuccessfulSagaResponse(@JsonProperty("body") String body) { - super(body); - } - -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/SagaEventFormat.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/SagaEventFormat.java deleted file mode 100644 index d035e96df..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/SagaEventFormat.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import org.apache.servicecomb.saga.core.SagaEvent; - -public interface SagaEventFormat { - - SagaEvent toSagaEvent(String sagaId, String eventType, String contentJson); -} diff --git a/saga-format/src/main/java/org/apache/servicecomb/saga/format/TransportAware.java b/saga-format/src/main/java/org/apache/servicecomb/saga/format/TransportAware.java deleted file mode 100644 index edcabf7d7..000000000 --- a/saga-format/src/main/java/org/apache/servicecomb/saga/format/TransportAware.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import org.apache.servicecomb.saga.transports.TransportFactory; -import org.apache.servicecomb.saga.core.Operation; - -interface TransportAware { - - Operation with(TransportFactory transport); -} diff --git a/saga-format/src/test/java/org/apache/servicecomb/saga/format/ChildrenExtractorTest.java b/saga-format/src/test/java/org/apache/servicecomb/saga/format/ChildrenExtractorTest.java deleted file mode 100644 index 1dad3613b..000000000 --- a/saga-format/src/test/java/org/apache/servicecomb/saga/format/ChildrenExtractorTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import java.util.Set; - -import org.apache.servicecomb.saga.core.SagaResponse; -import org.junit.Test; - -import org.apache.servicecomb.saga.core.SagaException; - -public class ChildrenExtractorTest { - - private static final String json = "{\n" - + " \"foo\": \"bar\",\n" - + " \"sagaChildren\": [\n" - + " \"id1\",\n" - + " \"id2\",\n" - + " \"id3\"\n" - + " ]\n" - + "}"; - - private final ChildrenExtractor extractor = new ChildrenExtractor(); - - @Test - public void extractsChildrenIdFromJson() throws Exception { - Set children = extractor.fromJson(json); - - assertThat(children, containsInAnyOrder("id1", "id2", "id3")); - } - - @Test - public void emptyChildrenIfNoSuchField() throws Exception { - Set children = extractor.fromJson("{}"); - - assertThat(children.isEmpty(), is(true)); - } - - @Test - public void emptyChildrenIfNoneResponse() throws Exception { - Set children = extractor.fromJson(SagaResponse.NONE_RESPONSE.body()); - - assertThat(children, containsInAnyOrder("none")); - } - - @Test - public void blowsUpWithInvalidJson() throws Exception { - try { - extractor.fromJson("blah"); - expectFailing(SagaException.class); - } catch (SagaException e) { - assertThat(e.getMessage(), is("Failed to deserialize json blah")); - } - } -} diff --git a/saga-format/src/test/java/org/apache/servicecomb/saga/format/JacksonFromJsonFormatTest.java b/saga-format/src/test/java/org/apache/servicecomb/saga/format/JacksonFromJsonFormatTest.java deleted file mode 100644 index bbf7510fe..000000000 --- a/saga-format/src/test/java/org/apache/servicecomb/saga/format/JacksonFromJsonFormatTest.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -import org.apache.servicecomb.saga.core.Operation; -import org.apache.servicecomb.saga.core.SagaException; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.SuccessfulSagaResponse; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import org.apache.servicecomb.saga.transports.RestTransport; -import org.apache.servicecomb.saga.transports.TransportFactory; -import org.hamcrest.Matchers; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import com.seanyinx.github.unit.scaffolding.AssertUtils; - -import org.apache.servicecomb.saga.core.SagaDefinition; - -public class JacksonFromJsonFormatTest { - - private static final String requests = "{\n" - + " \"requests\": [\n" - + " {\n" - + " \"id\": \"request-aaa\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"aaa\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/as\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"foo\": \"as\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/as\",\n" - + " \"params\": {\n" - + " \"query\": {\n" - + " \"bar\": \"as\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"fallback\": {\n" - + " \"type\": \"rest\",\n" - + " \"method\":\"put\",\n" - + " \"path\": \"/rest/as\"\n" - + " }\n" - + " },\n" - + " {\n" - + " \"id\": \"request-bbb\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"bbb\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/bs\",\n" - + " \"params\": {\n" - + " \"query\": {\n" - + " \"foo\": \"bs\"\n" - + " },\n" - + " \"json\": {\n" - + " \"body\": \"{ \\\"bar\\\": \\\"bs\\\" }\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"retries\": 4,\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/bs\"\n" - + " },\n" - + " \"fallback\": {\n" - + " \"type\": \"rest\",\n" - + " \"method\":\"put\",\n" - + " \"path\": \"/rest/bs\"\n" - + " }\n" - + " },\n" - + " {\n" - + " \"id\": \"request-ccc\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"ccc\",\n" - + " \"parents\": [\n" - + " \"request-aaa\",\n" - + " \"request-bbb\"\n" - + " ],\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/cs\",\n" - + " \"params\": {\n" - + " \"query\": {\n" - + " \"foo\": \"cs\"\n" - + " },\n" - + " \"form\": {\n" - + " \"bar\": \"cs\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"retries\": 5,\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/cs\"\n" - + " },\n" - + " \"fallback\": {\n" - + " \"type\": \"rest\",\n" - + " \"method\":\"put\",\n" - + " \"path\": \"/rest/cs\"\n" - + " }\n" - + " }\n" - + " ]\n" - + "}\n"; - - private final SagaResponse response11 = new SuccessfulSagaResponse(uniquify("response11")); - private final SagaResponse response12 = new SuccessfulSagaResponse(uniquify("response12")); - private final SagaResponse response13 = new SuccessfulSagaResponse(uniquify("response13")); - private final SagaResponse response21 = new SuccessfulSagaResponse(uniquify("response21")); - private final SagaResponse response22 = new SuccessfulSagaResponse(uniquify("response22")); - private final SagaResponse response23 = new SuccessfulSagaResponse(uniquify("response23")); - private final SagaResponse response31 = new SuccessfulSagaResponse(uniquify("response31")); - private final SagaResponse response32 = new SuccessfulSagaResponse(uniquify("response32")); - private final SagaResponse response33 = new SuccessfulSagaResponse(uniquify("response33")); - - private final RestTransport restTransport = Mockito.mock(RestTransport.class); - private final TransportFactory transportFactory = Mockito.mock(TransportFactory.class); - private final FromJsonFormat format = new JacksonFromJsonFormat(transportFactory); - - @Before - public void setUp() throws Exception { - when(transportFactory.restTransport()).thenReturn(restTransport); - - when(restTransport.with("aaa", "/rest/as", "post", singletonMap("form", singletonMap("foo", "as")))) - .thenReturn(response11); - when(restTransport.with("aaa", "/rest/as", "delete", singletonMap("query", singletonMap("bar", "as")))) - .thenReturn(response12); - when(restTransport.with("aaa", "/rest/as", "put", emptyMap())) - .thenReturn(response13); - - when(restTransport - .with("bbb", "/rest/bs", "post", mapOf("query", singletonMap("foo", "bs"), "json", singletonMap("body", "{ \"bar\": \"bs\" }")))) - .thenReturn(response21); - when(restTransport.with("bbb", "/rest/bs", "delete", emptyMap())) - .thenReturn(response22); - when(restTransport.with("bbb", "/rest/bs", "put", emptyMap())) - .thenReturn(response23); - - when(restTransport - .with("ccc", "/rest/cs", "post", mapOf("query", singletonMap("foo", "cs"), "form", singletonMap("bar", "cs")))) - .thenReturn(response31); - when(restTransport.with("ccc", "/rest/cs", "delete", emptyMap())) - .thenReturn(response32); - when(restTransport.with("ccc", "/rest/cs", "put", emptyMap())) - .thenReturn(response33); - } - - @Test - public void addTransportToDeserializedRequests() throws IOException { - SagaRequest[] sagaRequests = format.fromJson(requests).requests(); - - assertThat(collect(sagaRequests, SagaRequest::id), contains("request-aaa", "request-bbb", "request-ccc")); - assertThat(collect(sagaRequests, SagaRequest::serviceName), contains("aaa", "bbb", "ccc")); - assertThat(collect(sagaRequests, SagaRequest::type), Matchers - .contains(Operation.TYPE_REST, Operation.TYPE_REST, Operation.TYPE_REST)); - assertThat(collect(sagaRequests, (request) -> request.compensation().retries()), contains(3, 4, 5)); - assertThat(collect(sagaRequests, (request) -> request.fallback().type()), Matchers - .contains(Operation.TYPE_REST, Operation.TYPE_REST, Operation.TYPE_REST)); - - SagaResponse response = sagaRequests[0].transaction().send("aaa"); - assertThat(response, is(response11)); - - response = sagaRequests[0].compensation().send("aaa"); - assertThat(response, is(response12)); - - response = sagaRequests[0].fallback().send("aaa"); - assertThat(response, is(response13)); - assertThat(sagaRequests[0].parents().length, is(0)); - - response = sagaRequests[1].transaction().send("bbb"); - assertThat(response, is(response21)); - - response = sagaRequests[1].compensation().send("bbb"); - assertThat(response, is(response22)); - - response = sagaRequests[1].fallback().send("bbb"); - assertThat(response, is(response23)); - assertThat(sagaRequests[1].parents().length, is(0)); - - response = sagaRequests[2].transaction().send("ccc"); - assertThat(response, is(response31)); - - response = sagaRequests[2].compensation().send("ccc"); - assertThat(response, is(response32)); - - response = sagaRequests[2].fallback().send("ccc"); - assertThat(response, is(response33)); - assertArrayEquals(new String[]{"request-aaa", "request-bbb"}, sagaRequests[2].parents()); - } - - @Test - public void blowsUpWhenJsonIsInvalid() throws IOException { - String invalidRequest = "invalid-json"; - - try { - format.fromJson(invalidRequest); - AssertUtils.expectFailing(SagaException.class); - } catch (SagaException e) { - assertThat(e.getMessage(), is("Failed to interpret JSON invalid-json")); - } - } - - private Collection collect(SagaRequest[] requests, Function mapper) { - return Arrays.stream(requests) - .map(mapper) - .collect(Collectors.toList()); - } - - private Map> mapOf( - String key1, - Map value1, - String key2, - Map value2) { - - Map> map = new HashMap<>(); - map.put(key1, value1); - map.put(key2, value2); - return map; - } -} diff --git a/saga-format/src/test/java/org/apache/servicecomb/saga/format/JacksonRestOperationTest.java b/saga-format/src/test/java/org/apache/servicecomb/saga/format/JacksonRestOperationTest.java deleted file mode 100644 index 5c890a669..000000000 --- a/saga-format/src/test/java/org/apache/servicecomb/saga/format/JacksonRestOperationTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; -import static java.util.Collections.emptyMap; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.when; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.saga.core.Operation; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.transports.RestTransport; -import org.hamcrest.core.Is; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - -@SuppressWarnings("unchecked") -public class JacksonRestOperationTest { - - private final String address = uniquify("address"); - private final String path = uniquify("path"); - private final String method = "PUT"; - private final Map> params = new HashMap<>(); - - private final RestTransport transport = Mockito.mock(RestTransport.class); - private final JacksonRestOperation restOperation = new JacksonRestOperation(path, method, params); - - @Before - public void setUp() throws Exception { - restOperation.with(() -> transport); - } - - @Test - public void appendsResponseToForm() throws Exception { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Map.class); - when(transport.with(eq(address), eq(path), eq(method), argumentCaptor.capture())).thenReturn( - SagaResponse.EMPTY_RESPONSE); - - SagaResponse response = restOperation.send(address, Operation.SUCCESSFUL_SAGA_RESPONSE); - - assertThat(response, Is.is(SagaResponse.EMPTY_RESPONSE)); - - Map> updatedParams = argumentCaptor.getValue(); - assertThat(updatedParams.getOrDefault("form", emptyMap()).get("response"), Is.is(Operation.SUCCESSFUL_SAGA_RESPONSE.body())); - assertThat(params.isEmpty(), is(true)); - } -} diff --git a/saga-format/src/test/java/org/apache/servicecomb/saga/format/JsonRestSagaRequestTest.java b/saga-format/src/test/java/org/apache/servicecomb/saga/format/JsonRestSagaRequestTest.java deleted file mode 100644 index 7c0896d5e..000000000 --- a/saga-format/src/test/java/org/apache/servicecomb/saga/format/JsonRestSagaRequestTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; -import static org.apache.servicecomb.saga.core.Operation.TYPE_REST; -import static org.apache.servicecomb.saga.format.JacksonFallback.NOP_TRANSPORT_AWARE_FALLBACK; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.anyMap; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.servicecomb.saga.transports.TransportFactory; -import org.junit.Test; -import org.mockito.Mockito; - -import org.apache.servicecomb.saga.transports.RestTransport; - -public class JsonRestSagaRequestTest { - - private final RestTransport restTransport = Mockito.mock(RestTransport.class); - private final TransportFactory transportFactory = Mockito.mock(TransportFactory.class); - private final JacksonRestTransaction transaction = Mockito.mock(JacksonRestTransaction.class); - private final JacksonRestCompensation compensation = Mockito.mock(JacksonRestCompensation.class); - - @Test - public void blowsUpIfTransactionIsNotSpecified() { - try { - newSagaRequest(null, compensation, NOP_TRANSPORT_AWARE_FALLBACK); - - expectFailing(IllegalArgumentException.class); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("Invalid request with NO transaction specified")); - } - } - - @Test - public void blowsUpIfCompensationIsNotSpecified() { - try { - newSagaRequest(transaction, null, NOP_TRANSPORT_AWARE_FALLBACK); - - expectFailing(IllegalArgumentException.class); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("Invalid request with NO compensation specified")); - } - } - - @SuppressWarnings("unchecked") - @Test - public void defaultToNopFallbackIfNotSpecified() { - when(transportFactory.restTransport()).thenReturn(restTransport); - JsonRestSagaRequest request = newSagaRequest(transaction, compensation, null); - - request.with(transportFactory); - - request.fallback().send(uniquify("blah")); - - verify(restTransport, never()).with(anyString(), anyString(), anyString(), anyMap()); - } - - private JsonRestSagaRequest newSagaRequest( - JacksonRestTransaction transaction, - JacksonRestCompensation compensation, - JacksonFallback fallback) { - - return new JsonRestSagaRequest( - uniquify("id"), - uniquify("serviceName"), - TYPE_REST, - transaction, - compensation, - fallback, - null, - 0); - } -} diff --git a/saga-format/src/test/java/org/apache/servicecomb/saga/format/JsonSagaDefinitionTest.java b/saga-format/src/test/java/org/apache/servicecomb/saga/format/JsonSagaDefinitionTest.java deleted file mode 100644 index 6228b662b..000000000 --- a/saga-format/src/test/java/org/apache/servicecomb/saga/format/JsonSagaDefinitionTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import org.hamcrest.core.Is; -import org.junit.Test; - -public class JsonSagaDefinitionTest { - - @Test - public void backwardRecoveryIfNoPolicyProvided() { - JsonSagaDefinition definition = new JsonSagaDefinition(null, new JsonSagaRequest[0]); - - assertThat(definition.policy(), Is.is(JsonSagaDefinition.backwardRecovery)); - } -} diff --git a/saga-format/src/test/java/org/apache/servicecomb/saga/format/SagaEventFormatTest.java b/saga-format/src/test/java/org/apache/servicecomb/saga/format/SagaEventFormatTest.java deleted file mode 100644 index 9bad69cb2..000000000 --- a/saga-format/src/test/java/org/apache/servicecomb/saga/format/SagaEventFormatTest.java +++ /dev/null @@ -1,180 +0,0 @@ - -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.format; - -import static org.apache.servicecomb.saga.core.Operation.TYPE_REST; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.servicecomb.saga.core.JacksonToJsonFormat; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaRequestImpl; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.SuccessfulSagaResponse; -import org.apache.servicecomb.saga.core.ToJsonFormat; -import org.apache.servicecomb.saga.core.TransactionCompensatedEvent; -import org.apache.servicecomb.saga.core.TransactionFailedException; -import org.apache.servicecomb.saga.core.TransactionStartedEvent; -import org.apache.servicecomb.saga.transports.TransportFactory; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.seanyinx.github.unit.scaffolding.Randomness; - -import org.apache.servicecomb.saga.core.FailedSagaResponse; -import org.apache.servicecomb.saga.core.RestOperation; -import org.apache.servicecomb.saga.core.SagaEvent; -import org.apache.servicecomb.saga.core.TransactionAbortedEvent; -import org.apache.servicecomb.saga.core.TransactionEndedEvent; -import org.apache.servicecomb.saga.transports.RestTransport; - -public class SagaEventFormatTest { - - private final String sagaId = Randomness.uniquify("sagaId"); - private final SagaRequest request = new SagaRequestImpl( - sagaId, - Randomness.uniquify("serviceName"), - TYPE_REST, - new JacksonRestTransaction("/rest/xxx", "POST", singletonMap("query", singletonMap("foo", "xxx"))), - new JacksonRestCompensation("/rest/xxx", "DELETE", singletonMap("query", singletonMap("bar", "xxx"))), - new JacksonRestFallback(TYPE_REST, "/rest/xxx", "PUT", emptyMap()) - ); - - private final RestTransport restTransport = Mockito.mock(RestTransport.class); - private final TransportFactory transportFactory = Mockito.mock(TransportFactory.class); - private final SagaEventFormat toEventFormat = new JacksonSagaEventFormat(transportFactory); - private final ToJsonFormat toJsonFormat = new JacksonToJsonFormat(); - private final SuccessfulSagaResponse response = new SuccessfulSagaResponse("a wonderful day"); - - @Before - public void setUp() throws Exception { - when(transportFactory.restTransport()).thenReturn(restTransport); - } - - @After - public void tearDown() throws Exception { - verify(transportFactory, times(3)).restTransport(); - } - - @Test - public void transactionStartedEventCanBeSerializedAndDeserialized() throws JsonProcessingException { - TransactionStartedEvent event = new TransactionStartedEvent(sagaId, request); - String json = event.json(toJsonFormat); - - SagaEvent sagaEvent = toEventFormat - .toSagaEvent(sagaId, event.getClass().getSimpleName(), json); - - assertThat(sagaEvent, instanceOf(TransactionStartedEvent.class)); - assertThat(sagaEvent.sagaId, is(sagaId)); - assertThat(sagaEvent.payload(), eqToRequest(request)); - } - - @Test - public void transactionEndedEventCanBeSerializedAndDeserialized() throws JsonProcessingException { - TransactionEndedEvent event = new TransactionEndedEvent(sagaId, request, response); - String json = event.json(toJsonFormat); - - SagaEvent sagaEvent = toEventFormat - .toSagaEvent(sagaId, event.getClass().getSimpleName(), json); - - assertThat(sagaEvent, instanceOf(TransactionEndedEvent.class)); - assertThat(sagaEvent.sagaId, is(sagaId)); - assertThat(sagaEvent.payload(), eqToRequest(request)); - assertThat(((TransactionEndedEvent) sagaEvent).response(), eqToResponse(response)); - } - - @Test - public void TransactionAbortedEventCanBeSerializedAndDeserialized() throws JsonProcessingException { - TransactionFailedException exception = new TransactionFailedException("oops"); - SagaEvent event = new TransactionAbortedEvent(sagaId, request, exception); - String json = event.json(toJsonFormat); - - SagaEvent sagaEvent = toEventFormat - .toSagaEvent(sagaId, event.getClass().getSimpleName(), json); - - assertThat(sagaEvent, instanceOf(TransactionAbortedEvent.class)); - assertThat(sagaEvent.sagaId, is(sagaId)); - assertThat(sagaEvent.payload(), eqToRequest(request)); - assertThat(((TransactionAbortedEvent) sagaEvent).response(), eqToResponse(new FailedSagaResponse(exception))); - } - - @Test - public void compensationEndedEventCanBeSerializedAndDeserialized() throws JsonProcessingException { - TransactionCompensatedEvent event = new TransactionCompensatedEvent(sagaId, request, response); - String json = event.json(toJsonFormat); - - SagaEvent sagaEvent = toEventFormat - .toSagaEvent(sagaId, event.getClass().getSimpleName(), json); - - assertThat(sagaEvent, instanceOf(TransactionCompensatedEvent.class)); - assertThat(sagaEvent.sagaId, is(sagaId)); - assertThat(sagaEvent.payload(), eqToRequest(request)); - assertThat(((TransactionCompensatedEvent) sagaEvent).response(), eqToResponse(response)); - } - - private static Matcher eqToRequest(SagaRequest expected) { - return new TypeSafeMatcher() { - @Override - protected boolean matchesSafely(SagaRequest request) { - return expected.id().equals(request.id()) - && request.serviceName().equals(expected.serviceName()) - && request.task().equals(expected.task()) - && request.type().equals(expected.type()) - && ((RestOperation) request.transaction()).path().equals(((RestOperation) expected.transaction()).path()) - && ((RestOperation) request.transaction()).method().equals(((RestOperation) expected.transaction()).method()) - && ((RestOperation) request.compensation()).path().equals(((RestOperation) expected.compensation()).path()) - && ((RestOperation) request.compensation()).method().equals(((RestOperation) expected.compensation()).method()); - } - - @Override - public void describeTo(Description description) { - description.appendText(expected.toString()); - } - }; - - } - - private static Matcher eqToResponse(SagaResponse expected) { - return new TypeSafeMatcher() { - @Override - protected boolean matchesSafely(SagaResponse response) { - return expected.body().equals(response.body()) - && response.succeeded() == expected.succeeded(); - } - - @Override - public void describeTo(Description description) { - description.appendText(expected.toString()); - } - }; - } - -} diff --git a/saga-performance/README.md b/saga-performance/README.md deleted file mode 100644 index 7e4e55e49..000000000 --- a/saga-performance/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Saga Performance Test - -Performance test is automated with [JMeter](http://jmeter.apache.org/download_jmeter.cgi). A great tutorial can be found -at [Guru99](https://www.guru99.com/jmeter-performance-testing.html) if you are not familiar with JMeter. - -## How to Run Performance Test -To run performance test, execute the following JMeter command -``` -jmeter -n -t saga.jmx -l log.jtl -``` - -To generate test report from JMeter test log, run the following JMeter command -``` -jmeter -g log.jtl -o -``` - -## How to Enable Kamon Metrics -[Kamon](http://kamon.io/documentation/get-started/) is used to track saga performance and reports trace data to both log -and [StatsD](https://github.com/etsy/statsd/). The easiest way to visualize tracing reports is to use a [docker image](http://kamon.io/documentation/kamon-statsd/0.6.6/overview/) -composed with StatsD, [Graphite](http://graphite.wikidot.com/), and [Grafana](http://grafana.org/) - -1. Build saga with profile `perf`. -``` -mvn package -Pperf -``` - -2. Run saga with aspectj and Kamon enabled. -By default, tracing data will be reported to StatsD running on `localhost` and port `8125`. To change the default StatsD -host configuration, pass `-Dkamon.statsd.hostname=` and `-Dkamon.statsd.port=` as vm options when running -saga. -``` -java -javaagent:/path/to/aspectj-weaver.jar -Dkamon.modules.kamon-annotation.auto-start=yes -Dkamon.modules.kamon-log-reporter.auto-start=yes -Dkamon.modules.kamon-statsd.auto-start=yes -jar saga.jar -``` - -3. Add a new row with the following query in Grafana to display the segments of trace data. Please refer to [Grafana Tutorial](http://docs.grafana.org/guides/getting_started/) -if you need some help - -![Grafana Metrics](images/grafana.png) - -## Recommended Test Setup -Three test machines to run the following services on each: -* saga -* car service in saga-demo -* MySQL - -The car service and saga can share the same machine, since car service consumes very little CPU and memory, and has no disk -access. diff --git a/saga-performance/images/grafana.png b/saga-performance/images/grafana.png deleted file mode 100644 index 837b7778e2656fed1603e8aa053f8d5641187e46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15508 zcmdVBWmH^Svo4GV4Q>e*Ah-nx?hxGFJ%r%Fp>cw1f;)}7yC*ibc`76QMimAIUK#qn5cvu8 zH~HK4r_dKzCsipin2HgSE$ANz7NQEGFfi3IXg4N^(7#bWNb5Mkz+iO$^#j{yU-T9R zMu1-Cji|c2;a-OQ2QsOQO&9x$hVA7=G;kUtoW_?WQyj!l#x#cZrhzVvVgjDelg1ylhy-~`6JjYR$k_RdSMfpjwXxzc{g5vPSBvs z5pA7NPJ8*x<-&P%f@5?@;N-w#a`ePYpOf==NPuIh^Uhhx7jm(a>Cdd!fXrnB1OMvZ zSNSudFVf{vfl*c1=wD#|arv3Tzy={hb^cO%Z<^MLg_7(;m8ZTx%q|7Pd^&&Gf1{lX7EC+}Gc0kdE%pDG?*GyhvetEj&_cK_l`uN zza{*aO@U8fIbZg^+W@T&lxQb)iHF4)>k;mhGMZYND9T4+M0~CI6^R+qy#C@=4&qq~ zEN-J4a?{rZtQR zlXcpYtM(E@_V!t0uq}-?5q=Cbnenr4M9wrxfeN_-CNNKoVV+!v`H#a{y?v)rrfWa3 z9h;o?9KZV`i-5T4TSv(uR$11`#rJNJTrs3*$8{Yq3R=VtRdl?I%AjG2$0Uh;GB5s! z#4mLCe1yp#P1w(^D!zBs5p7{tv+=Z&1d_9iy2^Yrv3QZq{%+wJY>;10^ml@0ndCV)*DzrZ^|O8wUMuc9Ipz?KY?aj-C}_dse* zFce1rZFD>WG6e+~6Z3!Q7$rL*i~^IV&_tOcbX%4(qGu}i+h_1IIy#^v=tlNOzD^3OaHS>WCj97B zJ}d=fJolm9DofwbR2)#>g%6Q@*OOB#9mH2zsWMYJBxi!ZXyM`d9a~w=R5YSmf{lZV zHt`Jn_27AgUfH0=d2p^_!B>$;`W4PXg1%P)EXPCPSLdWp#f(3}YOSP{c2 zoiDBL5TNZ1W=j9q<+CY+Qnk0wQAiMAKARs>a^ViJM_e1*1psbL|6So~IxOMFTX&ihvoFct&ij`p9BI z=hVYvs1iS7XAjoC0zmOnj7M%05&mCF;x8P75EgwFo<1yyYXd2I@&Tm3R--Xc@d+wQ zk@BRpNo;(m^5h$#BI^xGooaTb?(Lzg$yZ-QpS4(YT@w`QA(zdDd#It&^sw4SYZ8?Z z;ww)xHhezj*Zh^cny(>%fCpDHBAMbjHvPEW`GL{#aFk7cWfI%o|oECZr7bC60_@a1q_G?S~vvcMuz&FBLz zmcE`7kX-SJ6~LB%P|yMZ6(Mu#)v`s&P;e9a}P1U^P) z3tD_N5wC5Ygm9u3y@%Dc*KiJMV~*mLj+iKRvM8fvyjuwN-xb3q7OPAq6l*kMnhSan ztmapA35Pg6ds|- z+=Z>TFg4!-_{Y;hQPTeHRe4|Eneqj`%%xAuA6~pl9xWB`)Y9t7(O;R$809Z`GdiH} z++o|#RV$33E}2mtgf`_CDw$Q+Ny;$WtYAFIP9X0&OS!!^(0Y?pM!uH&!eX}BkvuQn z&q@$=`Vc`v>R#dJY@K7K-XU*A%4;;C+57=!WLJvN$g#m!L*MZ~IQqod0mpqdE50Yu z3<2YK7f9kvI{|t0`#luvQk&b;*tCr~|-zp-q$4ACgeLt?kmiW?j_iE~= zsapY&RcN9$nJ}Yf%mGfh#7HBEzFBNNhWtIVyDqqNR*;VpD7gs=*Y#Gb$Gz3GUpg;J zjJ7~B8iBg&{yapoXYCHLKkYjDhr8Z9r~^w`$ED#3%ae6VHAdo0G`hz9?a&k!S^LWK zkKeS+tH&bX8bA42G1Yw{^C^sa{a#SiA!ej5Wg)&k+=wcjh4<9zC6NYKK;M~P;8w(N z1S*={Y=Io0;@xwn($n|REk>zYL)h9rp8DJSYv=huPhvCuu`e>ICRUTt;p=m4S1vjxIk(q~2@q3sUXQ+F zO%Tq)bCN6l3P%pW2VFV|Vy>vcS)NfJ#n$zyxp78(5~Lj-zimdGL;`Uu_ABbMz-q{! zPSWS_Q2=SCyuN{MuUkJbo-C01d>mzKB3&{zSGq#^h~4c$5TPe|x=ARuu~u|AaFf@` znoK}C`gzN2!wItl1Jn`6P1l)QxUIFzfwePOqww9<`-9MF7ZW+|#B{LU@gzjFTCi-w z3d>q%Xrv#O87zLOYV-U<9SZ>sd~{BZR0SM==i+-R1!8yG*^c3G8INVhda`Qs8$-Pw zSL)gHQLou^N9B1n?_M*$aYLo;QBS7PULo*`PT#BckyJOoK?xeqZ39*?_DG>}Vx|#t zC-<|%Hl~d}-S!!-E3a_BaL4>(h7)#caMZaV51C~lo|4+Wi0V7y84{Jec{xyJYw~oK z(nwhTVMc|fpzDtBr;53Lk7^P}hR#CX1N2wPuYVmQgIA92=eUutV|DfhX_BHWTnY&h z!w)$OU_oicbt#u3+C%$Is*!O@R^BND1nDZo&a5O=uC3;l(KqY-Na< zUKP6Z>|Xt@5lGwd?y@NPaTk*9l3GGcK5a*_Jb=^qp|~CY7S%{$zyNls1qhS8N%PJ% zgvWi_b$8gS$AUbu&n=8x78cTN(AqOr>o4*YA@NwG_@}0H3S>S;cMxN_SW1|svQ>3g zh@o9~W%ZTn%>cxQvQUai#=YJ^WGm=>Ky=yNWg`g!k;_i8-C)3nWaf=HltCxWLyOv? zgGPo;i_}pn^eFl8qv|z~U7I`XTNFC$kba;cMzQ^-OzRxT^As3=gV*EQ=o56J`;p7V zz-LxJODnr$yVWPV+-cJDR`Juiac1Q_;_cH87JOyB1_W%puTraKIZ{%J-!Ss8UiSSs zEJ`Nf7)q%spE6Su)uXZHZN)=3)Uo?XRT#*=(XMZh=mC3=Xkv)$JA?B^8#egq5sUZ1FGE_4ssyow z87QUOe}1f*$u|DNMe@x~qZgTub(uA7$z| zrI>Y^w?g_dtX>XjlA;|$GcLJA&TzQ_eFkI(-gGmr!9x+=6qmp3PR6&U8Q<}#DQr0) zXs&&1_g3~eGTp50W>?Um+p zvVb~ST#ps!7(c*TMO^Hj1&F)C#yzM4aH&)6aPHtR+?WfuU4oREV0sqM!vn}C;O6eX zuVl!sr@GvuQXr$F2IiHoqa9A>^7n*@t>EG-Uw6nVFY!}W#LjsAn&$`2)*ol`*;)*r zuwZLN?P7WEs|S>~A(bw{$;NaoNW4#vPJwidfnDP=qHjx_UM!@3C!PL_8-OHf z2m7g#=3eTnX|V29OOtB2jFcPkjf-G}H|5T^3|IB(&Uh|O_bnso*144Xq4EWB4GB^L zPQRFni%2w$?WLV2H)Z+=ayO36+2D6=CMI-fN}8glxvDPAoizI~@01NX$ejm_KxBF7 zOqXW_nSgLdyBi$3+*CJp05AM0P_y4x9p#&%toj;6)F z?aeL(y;zHIn+{%^a}J`~EOk^L!PYE+*$r_^6C<-}A@QG5l|I!DYRK)j>*&@%FDG&l zkpH~CGu#(@CT&ymDa?69m3AamxxG#ic&a|kQXze`&i>x4w^dq1=3s0riK}N$N-FZz zv(L*fPwqqgT2#^UYGW35;zOI&&|Z2nDTtH{L;MINpRW8wE&AaRmhF2XiKvdh^4533 z5SFv7`}}!;w{nAyOoR+VZWXcJugo)7nyNDXCYrLhiXKRB7wT$wW)9)pzXNGIPT3LE zf7Qoq&Xk=ONEA@9NX5I?MNqz(hilwx{HRjC;~ghbdww7ROAXGLc=y8IMF!Q4-!Ut7 z)42L2@c%fd$+ELnXcG0~!%VQVQmG%6pCJu_w9-Q>u%CeGK;;BYXtj>wkV{dSiU zx0=YFUr9#G@G2+OZR00h<xV7BxwRrH|!08pa<fm8T5+JR7-PQp=jvwz|B#aKPgbRV;pktQ z8p5LvG3TcQ%*apeKsj6b=>3NYy!6WnT3+TXTN4WdsCmiOxJxdbT%aUBfZ zUv^0f6Enu9&pIv;)Ug8Wgxx-`aXu#@OEMh&ahoSrR+mIq9XXB|kCCF;1;#c}(R&i` z22-=d&8(MJwC&fgwc=U@I0kD6LC<@>nE_9>x%;pJ3+Q{9q!{D*L)u&TjqsWoAdmRG4)$*_`sGWwKl=<_F3qNVNB;h z#sWwHs^Rq3;7H@Xv@P2SJmrdr9sH-+uhQ-^RuoH7WOVe>l4ST63UtfKIBMf&c@nY# zezF97a}-|di0U7}rIM~;Qqf3Gm73=Bb>A7A>(xZI!hR`Us(u%ZRLbGb&2ao;E5cN`VI`1*eNEQF>HgiV=c?HL5GMG zu{8o-`!IRTl-b>VwwSV08!0zZb?UTV~$K)xTrm68x-849oC*+>!|TdUIHdgj5Vkq(TD?Mu)8 zkFJGQnVxS%I1`1G&J&e+Wk0f08ohB0lrFE};IN|oDT}#Q&mh#v)`AxqS`m)O|2#j5 zFDuq*?Ky?dkp_M)Re?XZrGe|lZd*(CXEruYOChloHnCQLMuQL-bh|79G(cUO9AbR> zD4u%^8NO0KcJl{~j!-{TvAtA+^bdjZyqJ@r?gGq#tSqsvbO*EaN76D!d2h5J2Clu{?DyO{ts_wW`X#J2G!UIzjcl3) zSJ_H5w3zp&hGQa|QdT2gnNU;3MgosXt_R`g@04n{(@f7_(cF`xtW2D{X|~s|Zd|MjMmbDp|Re?q`y?ApE*eD`{`8lQiZ`S9L&IXg|OHDdhfaZwP} zDmX}1_l=kj`B7AA%W0R4u=Db)ioFO4Ts7W*xCr` zA`qo3cx$9ym5jFeeUSXm>+9Op9WvCSZ*NZBZyTvnjWEP=6D=~XK2f=fd~q&g*H&i~ zXHmhmp`@<5Kolj56CoUy7a$J?Gd{ z(1fhgjxN_hPJMT_?%&N;b0frO6s|$!2!RV2r|(`H4y37a#qW_`i#JzrZ?bH8&ttKY zlG-kE&;a4EomAWKuuDh7r6d)km!hRW^q%|i2E787K59GWL!&}06GvbA4VCsDcC6wx%X;kZDWBb>-B<-x>F4s#PR;c6%rZU2M4AV4;kj6o6*-h;L^KXp;|XlZ1Zur0ybg_s?-w=$ z?9Fvp!=A<^P`EOl(9|{bCaKtN?f1T(VgbH=<9AcljDc-)h3&j8Z&cf;b4Go<_sviA zmXz<=l4+;7RI@U-_d6ghLVRXZvW3U#uoa!Vof06^1|%thZzK-~J4MRci%pzpo!GBQ zUTc_2il()6e6>EUVOgpsGWSX0YUTLqh$UsGo4=+I{JG!7K{+zb<0AlHXf8xA$)vo` z)TGKlBW9(kl4lTq0ggjE9`%q3BDvf@)gy_XTfCeRjtdO)8;~Eej zC?J?8H&FID$gc}t<1;Lj#|bA)&tl~n2y*m)5Py#Zk6aX~p%ce0_J!5U8etU1am5`|g#zjxxa`;rc1d-@mZ)#2z$J>!=1P z+rxHRUMlUJXs}OnlJRt5vV|n_Ce>;6tuAm6SLe0!B{uAFZ^oW)YkNWToR};tqw{US zuYM1B&XUN@mzr5F2syDle1Mtav~PHu(IEJKgnDnPy3V#Y-RWZcpl)wxLx0?mRBnOn z)#hURHNR~uIQ_RIIN8b3_w7Me=+4~^fy12dU5qhI_WfH|8}H`+6xebh??J_Q!_r22tCnw}ZR=3;11{bp4^ABI)oy4%cqe4`TQ`?U z^l$eUAOAt|5jg(g-;zrvBh8*?Zu73KkE$0Q{pfvEz4wSPq>eWc8jJA;y$4AGupL|9 zU$K~Xt$p-M;c;%sN7decyCL})ldRW|kbixIoc3|9hQH(8^r-3{Ir=FcDeneAtnM!& z^B>oB0(2QekIJe4QF(bRvfP$b^>gRSJ+80c<(BWz?^lqYX&vmp6dAvug|7YdU@;et zp*5b2*(^uT}4DmV-2<^$j@#Q4yCH zfn!Ns`=@AyMkh;_{Dp#*M!VqBt5as9j{LqPfaXimj=ArRr+C%ol?Dr}<|}GaB-lwt zJy#E&{8cNkHHqyIS+-`KZ@b$1KNI)sVS2TUa1&oAl4T8)OjvFu)f^U6{grYwiZ}l% zRl=3PqpKI^nfor-v#!;+9-p~&BxFGiu3xMfUw?p*JJHg>azCjCT7D&D7D5ro8W>J$ z3Gmw%*_=!2swmAK^~~}ab~A+3L0WvOeJeL68ojO(GhJu0To=KAO`PdE+orca_h9oP zt^ca0t``Hh(KhPu>u{M%5{+F360a`B=&_t-DSMczx>`mjmUcl)KCAGH@<75gsn3P7~t&~`>o=^k&L#O zhfrrQp@B1}{^a;nLv$hQC&+out~%f!mh)-EYUH>1@{I+4> z(~j6L@;_U;EqiiiovrOWslNDP;&6E=R1MiKPuKuM`l@FiL5C7KF#XUAj$0C6(J=f!g4 zVel+Xy1T6FkD zzECAUzxUaK(cCS*!<+(}=VBvW1<#$ax4BA{xF&PfU7{`X)x48fnXOIe)8-5zW#-EI zyh7u-4O{D$^%h+l_aAjEqft?u4yG}_<}I5&soMP278COyKOutd=25B(<&sN-qFBCJ zpGCW$xW!{+%wbtzOdWaWx38`>1KVwEEPAqS%MaQw)_AYdHmor-cxe^)ZEqp(M6<_Z zFBez8{U|N8z^SkI^*5xbyW(!LoRBW4-~kdH}IJ`z@=3brrJ0l$JOdXn3QrQCm8+a zgw%V&wpLK<43M2kTeTcAn;C8^sC#-rLNF@qD@HPVi(So039KM6gLJTtdK)eJdOLU~ zC@M*&xR&~MeBgaw7@|6@w7RTyEG&pk<7cqa$g1cJNt;!>K zMCGt0xS9Vcmh?L&zWsMbm$r%LE>~Usg4eoh^Xa4?$Diiz-lU(KykxZy`Wa>0?8R7J zO}E_2*$waV3*X_&TMy(JGehTSbtWQ{?I1Ahsac^I@9}xc{+&uIPmO_rWj{mgL(4chBa0d{F@g6s$GHDE^ATCy78 zc3j+f?i1(6cQd$}1gp@1u$IucRANhBPQxi8w*(h?&w zE4twOdC!eJ9fRD=^+ncLBx(#yiBUIA?YDEng?$2y=T9l z@fE3g+VC51E7h^|bQMtAO8#8*pHL){=vUcuyozLx#VXSWnSrNn(q8I_`)VHgL;1Eqb6 zy_TG=clEOd*q{+N7A9Ne*4U#yT3LvW< zcgZ&3F5+$b)WQUtCpb8u%I zK_n)cG&Yy8?HM|$H{T^}uuR>tIs6LN33eSG$hvNi<8G{YUTKQmv0I;iVu`4hj4>fP zuuW7nk|vmiqe@Kf&&p3}BxIxqnlc09j5fiIx#F?3z1Ywo(heh(nLEvE$Ufp_7`b0M zmua+({x!a*5pf@~XWYvXFp@K|UtII_pmZ6{E{*8kx1*txtkUbSEM_;8kX2tg8C-Q9 zc{x1`B?#0mmhcG4`&VnO40aODUd>wCkojKd80sYys=2vb6=1k?C0PhyvJg9H=B)UX zEQPiU%LUFSl^X$!r!syfU*1bz=eRIp>4x3r7Bq~sv&?tWjc3Mhg*K*=$Fl(SDBA z1&Zk8Vc3_(qOeQt5_qSdMQt@0ucx0!gL$`>X0}mK?rcDRv^;3a?~M`9n4=q3SWe?L z%Jd?e;4^ZAqluS!l$n(NYLw^+ngAEW269w^_1-sClu@;H3`03seBZBqQir?uKd+t| zcAZlvP5Kqg)yRwMtZ_$K!<%FWs!v9&0lWh`#bYE?i885d;{Cz_+$1J(G(dI&=}-W0 z(HY7L=RulR87X_z`{=FNqIMPa=Ky%|qOrG5?m)*iR>Oj8k7eYdjjHk{?rGGbwVa&o92yQ$x(&z;U<7`AaNywzephJ$dU&=rb5x38>0 zu%6~f9UR5C>L;~nTwa6ns%y~;~RKUnydteO7)-pdehF2UA-Eb9qcEoiYo=o^k!NE+)16U>-N4dSh zFZ6lOLv<$gQ#+=>QBKp%3dh&;jFVM(>h4Qf?w2%6Mu!gOM+?{D+#b2p!=hza zgj0H?;iHmDKrA6{k_s{8tYab0Kt(T|Gwt^#Z!y$& zu!JfR;;nrJJ4>h7H<*t%*>g9`Qr1Ut2f2*&)H7?Rv$@BVGqeQ+WJZ!BCF(Z~jGR%iAbnJg39u3`sx-SO`Xc+}6OlGu`wYpjx z=mXiQPnnYottH$69xbK6>M>R#mT5WA*#_awyEX^W*{5-im+SOBU0Vx~v~jNCm={{K z@f5XbsF6&=q1kykKJu_3ICDOY5&d=9Z@xro$sR=&M zLQ{*CFUX7xmby~T;0>iv$N;w4h&^9zXy8+EHkU3I%CSlRi0Hc=nFG5`s!>WD>dvp~ zC3igw)|ege33I`{-C1G_1tB_wILcg$3?^eh8`yQ0yxjTDCc>ihr0PWWvo(HY2c<%M zEbP{nbz;w%?VU+6Op`etE`{|jcmFs7|8Q1Hik%XEHx?FGVtpe|!U!MmE~EH;s@B zgrnc$R~`nNjvJQFl9cpZNwQ@Z9+TWEs!f*SLH$dWY7K?%PSes_6AWI}K}`C3kSbI# zYgYREW+t!9D{YBwE&ht~3w~v0kY>l&%=l9oh0)4|@9l|MZRf>_2RPZ*%!!otneYiQ zeQj4~do9rmzH!?|^XDZo=c{CX3Z~^&q?P&d z7hXnfUZROx^Czn!VfMmPt7k=D?@}nzITt&vbX=}4>Z`^OU2CtHn1HAwah996xS;WO z1+0x)G9IOxJr}M7_f?gDGYY`3NBLErcR_xB;eqC7Xl@VZ=MU0pp`#;sB+S0$t>ZF@+AWk-9ta^4z-xI_S7aps(yT7%dKZtqM zzV0=)W=S+&0iB|BEqlnGKhyq!OgL+nH=sL7i=N497_ns9*s|6|&JC8iHXi`)gHN4O zXo9{cpoCSn%6m0u+1u0&vOrJf(Do8ZcO&QZj@9LK)6uh^cR~qitS*SKQ~nr9tU*f^ zPq0_C%baG59e)w-130rf)(0C;olD53u1Fp@g6%q&#-&oDfv&=6cW%^_VcFV86DfeG zmAwfUpf$8LkBJ5AnX`yn=xO=4xS99a!zrJ5u&(0u#ltBd%)~YxHTs*+`I{M;Jd0&^ zBsY4VLTSn3WcxR_!Cq!_Ztqo_ZND|QdptL^`CI-#lA>0}^87yt3XBOKeG%j9y&qNz4_Wp8f;2|0~q7lu3<^ISe;CUbF9w zc>WEVtJ7381oBQC%I{#LxeW^b!EJRUzR?am*FvM0x2Xq;3n^GaVwZehNzR(DFP0zR z-a_c>5X${ys1HS4pcN2zOUU@QI{t&dsi65`jsIijnmQk-nY}8H#>HBw6&ojlzSo60 z#6fR53+5h}CG^?AD$Fjw*(%t-yYe3!#h*iqNN;d+u>TtyZWwZS+luKci@w{GRZc_v zDz-}+^GQ`tKt2D$oyfZHnae@x;BhO<&f4IcAc>+QhcS6(ST{1=t4 z90l8nIH@2j&>!W^>uQKEhoRSPKgG=ZpiIFs~b0j%2{`5 zB0N=i2%?yLB0Jb;h0EiTq8!vt0@Qr9${eSg}q9fAvW@Aq-} z*Deyq_gQ^?GZx1)g|8*p4ppuoG2aySP6R673t4q!4ycyb7z^(r{Ubukm41NZ$R?W^ zY=^n-%23SrY-c%5r=umvMG(*zjArkaS)WxcU#!)O9n&1p0Y(Q!&wOz_#P`6(;pn0= zA}ntc%tQZ#;65w###2t{poKL_)_&|Jp*<5-Dd@3W`5SD1EA&Z5VCLoLBQ67GmfL6? zL?-1ixz}s;))IA|s6tJ!0x* zInS>fyVb=`*)dl``Ng~*!_TL#`+z^JDG^VENu+|FAGn*&)h6R_$?-+EH8`;-_`zMlnw`-=@+bwz>czGvr+xL#X5fA~7JAg+g zrR(RbKdna;xb2hGel0`X%@JA~Vc{1-nLLHX9vG7iK{KHBMzE&)U0f;${)j)62K>&& zjA18@eZq0pY81w~j;-1y4i-oK3)55Q1+Me)xwA-=j!r zgGT6CCqYvZ-ko9f!l4n?!ghK0--O>BT=Y}vewgzm)QUl%wA@WH-7|XIlH^02etnka z|4J`*t8o;v-_mqBeQ&9#ho-0Uhqa0$sJyVx^CEGTayy~0=ayU!t&amvcGMpruYVns z6?$DUgz_2wo$}Kszy1b@jd_K>tg+{O1F2KE{Yz}ySI5?Vz1xs zIUnAKX_;#;SNh@$*{`;t_Q%07+}&i|IvqQ>EGgxSc&aUnFDaoFZ9d;>gp&mySc}dR ze01g-FF9sJj3-e1>g{}&&#honmVEE45R4_8?P|EpUuiJpqVCQh@Q*D923_6k1!o{D zWez(i4o5>$B*+Q4R_!^mqj9y|=~h!k$Z#sMbZ-3O#qoZEU)a4`m-y{n9i9+F-DorT zD|eJ%%bv%UcdS!EG|#9LVhrSl>Yk3}ZZJqh8#K;&w5_+g%1fO}_8M;cs`rHQ!jl?H zrrMWqv~&l$d@USaIo@lnSA#=8a`&HFQqXN0;a5k<&?e;Tnt%0~#r(&1@xlos9!DiY zc=T96Cng?SS(t~F#rHCD84h!D$Mi5571{<9eZPl^D3-r|C**K=FN-;$asi+gxRW7i z)402fJYK!A-xRt)G6YUQd12tPYJ}o9>ft@7%qA=-0VSxlq-F?la|8);8*tyVlEO8) z(zxIC@UHs|6yw^a>GX1 ztkvIpswxw?+itn+mmnVV##bTRvl( zC`VFTf@+p3osbNk${+I7DB@(dB-T~C)~Z4qeY?WUw|r22m8BGb z91FMdTa^ei&frqkAGTmKd{CHhh08%F8K3H>$!v-g>LZc9zj7|({~@(r-iZiQRe~`7 zl-chQCoj3-VL=@=q<@+pnz_ZoXq&752WcoCjd|{-rGroY@O}JZ4||qkj|3O~KV%gbM3VTQcO}sGe>DO9w?Ri}H`9P6bezcczpVWI=JI|hRqTD>TkcZm Qlf*DG5{hps#Eb*}Kf8wQE&u=k diff --git a/saga-performance/scripts/saga.jmx b/saga-performance/scripts/saga.jmx deleted file mode 100644 index 03f5cdcdc..000000000 --- a/saga-performance/scripts/saga.jmx +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - false - false - - - - - - - - continue - - false - -1 - - 200 - 100 - 1503917597000 - 1503917597000 - true - 700 - - - - - true - - - - false - - = - - - - localhost - 8080 - - - - 6 - - - - - - - - Content-Type - application/json - - - - - - true - - - - false - [ - { - "id": "request-car", - "type": "rest", - "serviceName": "localhost:9090", - "transaction": { - "method": "post", - "path": "/rentals", - "params": { - "json": { - "body": "{ \"customerId\": \"mike\" }" - } - } - }, - "compensation": { - "method": "put", - "path": "/rentals", - "params": { - "json": { - "body": "{ \"customerId\": \"mike\" }" - } - } - } - } -] - = - - - - - - - - requests - POST - true - false - true - false - - - - - - - 100 - - - - - 200 - - Assertion.response_code - false - 2 - - - - - false - - saveConfig - - - true - true - true - - true - true - true - true - false - true - true - false - false - false - true - false - false - false - true - 0 - true - true - true - true - true - - - - - - - false - - saveConfig - - - true - true - true - - true - true - true - true - false - true - true - false - false - false - true - false - false - false - true - 0 - true - true - true - true - true - - - - - - - false - - saveConfig - - - true - true - true - - true - true - true - true - false - true - true - false - false - false - true - false - false - false - true - 0 - true - true - true - true - true - - - - - - - false - - saveConfig - - - true - true - true - - true - true - true - true - false - true - true - false - false - false - true - false - false - false - true - 0 - true - true - true - true - true - - - - - - - - true - - - - diff --git a/saga-persistence/pom.xml b/saga-persistence/pom.xml deleted file mode 100644 index 5f7bc20f6..000000000 --- a/saga-persistence/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - saga - org.apache.servicecomb.saga - 0.0.3-SNAPSHOT - - 4.0.0 - - saga-persistence - pom - - saga-persistence-jpa - - - - diff --git a/saga-persistence/saga-persistence-jpa/pom.xml b/saga-persistence/saga-persistence-jpa/pom.xml deleted file mode 100644 index 372b383e2..000000000 --- a/saga-persistence/saga-persistence-jpa/pom.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - saga-persistence - org.apache.servicecomb.saga - 0.0.3-SNAPSHOT - - 4.0.0 - - saga-persistence-jpa - - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-aop - - - org.springframework.boot - spring-boot-starter-jdbc - - - javax.transaction - javax.transaction-api - - - org.springframework.data - spring-data-jpa - - - org.aspectj - aspectjrt - - - - - org.springframework - spring-aspects - - - org.eclipse.persistence - org.eclipse.persistence.jpa - - - - - - - com.ethlo.persistence.tools - eclipselink-maven-plugin - - - - - diff --git a/saga-persistence/saga-persistence-jpa/src/main/java/org/apache/servicecomb/saga/persistence/jpa/EclipseLinkJpaConfiguration.java b/saga-persistence/saga-persistence-jpa/src/main/java/org/apache/servicecomb/saga/persistence/jpa/EclipseLinkJpaConfiguration.java deleted file mode 100644 index 1ad78798f..000000000 --- a/saga-persistence/saga-persistence-jpa/src/main/java/org/apache/servicecomb/saga/persistence/jpa/EclipseLinkJpaConfiguration.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.persistence.jpa; - -import java.util.Collections; -import java.util.Map; - -import javax.sql.DataSource; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; -import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; -import org.springframework.context.annotation.Configuration; -import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; -import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter; -import org.springframework.transaction.jta.JtaTransactionManager; - -@Configuration -public class EclipseLinkJpaConfiguration extends JpaBaseConfiguration { - EclipseLinkJpaConfiguration(DataSource dataSource, - JpaProperties properties, - ObjectProvider jtaTransactionManagerProvider) { - super(dataSource, properties, jtaTransactionManagerProvider); - } - - @Override - protected AbstractJpaVendorAdapter createJpaVendorAdapter() { - return new EclipseLinkJpaVendorAdapter(); - } - - @Override - protected Map getVendorProperties() { - return Collections.singletonMap("eclipselink.weaving", "false"); - } -} diff --git a/saga-persistence/saga-persistence-jpa/src/main/resources/META-INF/spring.factories b/saga-persistence/saga-persistence-jpa/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 1d6b85033..000000000 --- a/saga-persistence/saga-persistence-jpa/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,18 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.apache.servicecomb.saga.persistence.jpa.EclipseLinkJpaConfiguration diff --git a/saga-spring/pom.xml b/saga-spring/pom.xml deleted file mode 100755 index 38f51ccd2..000000000 --- a/saga-spring/pom.xml +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - saga - org.apache.servicecomb.saga - 0.0.3-SNAPSHOT - - 4.0.0 - - saga-spring - Saga::Spring - - - - - org.apache.commons - commons-lang3 - 3.6 - - - - org.springframework - spring-jdbc - ${spring.version} - - - org.springframework.boot - spring-boot-starter-test - ${spring.boot.version} - - - org.json - json - - - test - - - io.servicecomb - spring-boot-starter-provider - ${java.chassis.version} - - - com.google.code.findbugs - annotations - - - - - io.servicecomb - java-chassis-dependencies - ${java.chassis.version} - pom - import - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - - - - org.apache.servicecomb.saga - saga-core - - - org.apache.servicecomb.saga - saga-format - - - com.fasterxml.jackson.core - * - - - - - org.apache.servicecomb.saga.transports - transport-httpclient-spring - - - org.apache.servicecomb.saga.discovery - saga-discovery-servicecenter - - - commons-io - commons-io - - - org.springframework.boot - spring-boot-starter - - - ch.qos.logback - * - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - javax.persistence - javax.persistence-api - - - org.apache.servicecomb.saga - saga-persistence-jpa - - - org.postgresql - postgresql - runtime - - - io.kamon - kamon-core_2.12 - - - io.kamon - kamon-annotation_2.12 - - - com.lmax - disruptor - - - - com.h2database - h2 - test - - - org.springframework.boot - spring-boot-starter-test - test - - - com.github.tomakehurst - wiremock-standalone - - - com.github.seanyinx - unit-scaffolding - - - io.rest-assured - rest-assured - test - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - perf - - - io.kamon - kamon-log-reporter_2.12 - - - io.kamon - kamon-statsd_2.12 - - - io.kamon - kamon-autoweave_2.12 - - - org.aspectj - aspectjweaver - - - - - - diff --git a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/JpaPersistentStore.java b/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/JpaPersistentStore.java deleted file mode 100644 index 4c6e5f07d..000000000 --- a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/JpaPersistentStore.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.saga.core.EventEnvelope; -import org.apache.servicecomb.saga.core.ToJsonFormat; -import org.apache.servicecomb.saga.format.SagaEventFormat; -import org.apache.servicecomb.saga.core.PersistentStore; -import org.apache.servicecomb.saga.core.SagaEvent; - -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -class JpaPersistentStore implements PersistentStore { - - private final SagaEventRepo repo; - private final SagaEventFormat sagaEventFormat; - private final ToJsonFormat toJsonFormat; - - JpaPersistentStore(SagaEventRepo repo, ToJsonFormat toJsonFormat, SagaEventFormat sagaEventFormat) { - this.repo = repo; - this.sagaEventFormat = sagaEventFormat; - this.toJsonFormat = toJsonFormat; - } - - @Override - public Map> findPendingSagaEvents() { - List events = repo.findIncompleteSagaEventsGroupBySagaId(); - - Map> pendingEvents = new HashMap<>(); - for (SagaEventEntity event : events) { - pendingEvents.computeIfAbsent(event.sagaId(), id -> new LinkedList<>()); - pendingEvents.get(event.sagaId()).add( - new EventEnvelope( - event.id(), - event.creationTime(), - sagaEventFormat.toSagaEvent(event.sagaId(), event.type(), event.contentJson()))); - } - - return pendingEvents; - } - - @Segment(name = "save", category = "database", library = "kamon") - @Override - public void offer(SagaEvent event) { - repo.save(new SagaEventEntity(event.sagaId, event.getClass().getSimpleName(), event.json(toJsonFormat))); - } -} diff --git a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaController.java b/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaController.java deleted file mode 100644 index 1a73b7bfb..000000000 --- a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaController.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY; -import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE; -import static javax.ws.rs.core.Response.Status.BAD_REQUEST; -import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.GET; -import static org.springframework.web.bind.annotation.RequestMethod.POST; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.saga.core.SagaResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import com.fasterxml.jackson.annotation.JsonAutoDetect; - -import io.servicecomb.provider.rest.common.RestSchema; -import org.apache.servicecomb.saga.core.SagaException; -import org.apache.servicecomb.saga.core.application.SagaExecutionComponent; -import io.servicecomb.swagger.invocation.exception.InvocationException; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import kamon.annotation.EnableKamon; -import kamon.annotation.Trace; - -@EnableKamon -@Controller -@RequestMapping("/") -@RestSchema(schemaId = "saga-endpoint") -public class SagaController { - - private final SagaExecutionComponent sagaExecutionComponent; - private final SagaEventRepo repo; - private final SagaExecutionQueryService queryService; - private final SimpleDateFormat dateFormat; - - @Autowired - public SagaController(SagaExecutionComponent sagaExecutionComponent, SagaEventRepo repo, - SagaExecutionQueryService queryService) { - this.sagaExecutionComponent = sagaExecutionComponent; - this.repo = repo; - this.queryService = queryService; - this.dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - } - - @Trace("processRequests") - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "success"), - @ApiResponse(code = 400, response = String.class, message = "illegal request content"), - @ApiResponse(code = 500, response = String.class, message = "transaction failed") - }) - @CrossOrigin - @RequestMapping(value = "requests", method = POST, consumes = TEXT_PLAIN_VALUE, produces = TEXT_PLAIN_VALUE) - public ResponseEntity processRequests(@RequestBody String request) { - try { - SagaResponse response = sagaExecutionComponent.run(request); - if (response.succeeded()) { - return ResponseEntity.ok("success"); - } else { - throw new InvocationException(INTERNAL_SERVER_ERROR, response.body()); - } - } catch (SagaException se) { - throw new InvocationException(BAD_REQUEST, se); - } - } - - @RequestMapping(value = "events", method = GET) - public ResponseEntity>> allEvents() { - Iterable entities = repo.findAll(); - - Map> events = new LinkedHashMap<>(); - entities.forEach(e -> { - events.computeIfAbsent(e.sagaId(), id -> new LinkedList<>()); - events.get(e.sagaId()).add(new SagaEventVo(e.id(), e.sagaId(), e.creationTime(), e.type(), e.contentJson())); - }); - - return ResponseEntity.ok(events); - } - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "success"), - @ApiResponse(code = 400, response = String.class, message = "illegal request content"), - }) - @CrossOrigin - @RequestMapping(value = "requests", method = GET) - public ResponseEntity queryExecutions( - @RequestParam(name = "pageIndex") String pageIndex, - @RequestParam(name = "pageSize") String pageSize, - @RequestParam(name = "startTime") String startTime, - @RequestParam(name = "endTime") String endTime) { - if (isRequestParamValid(pageIndex, pageSize, startTime, endTime)) { - try { - return ResponseEntity.ok(queryService.querySagaExecution(pageIndex, pageSize, startTime, endTime)); - } catch (ParseException ignored) { - throw new InvocationException(BAD_REQUEST, "illegal request content"); - } - } else { - throw new InvocationException(BAD_REQUEST, "illegal request content"); - } - } - - private boolean isRequestParamValid(String pageIndex, String pageSize, String startTime, String endTime) { - try { - if (Integer.parseInt(pageIndex) >= 0 && Integer.parseInt(pageSize) > 0) { - Date start = "NaN-NaN-NaN NaN:NaN:NaN".equals(startTime) ? new Date(0) : this.dateFormat.parse(startTime); - Date end = - "NaN-NaN-NaN NaN:NaN:NaN".equals(endTime) ? new Date(Long.MAX_VALUE) : this.dateFormat.parse(endTime); - return start.getTime() <= end.getTime(); - } - } catch (NumberFormatException | ParseException ignored) { - } - return false; - } - - @ApiResponses({ - @ApiResponse(code = 200, response = String.class, message = "success"), - }) - @CrossOrigin - @RequestMapping(value = "requests/{sagaId}", method = GET) - public ResponseEntity queryExecutionDetail(@PathVariable String sagaId) { - return ResponseEntity.ok(queryService.querySagaExecutionDetail(sagaId)); - } - - @JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE) - private static class SagaEventVo extends SagaEventEntity { - - private SagaEventVo(long id, String sagaId, long creationTime, String type, String contentJson) { - super(id, sagaId, creationTime, type, contentJson); - } - } - - @JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE) - static class SagaExecutionQueryResult { - public int pageIndex; - public int pageSize; - public int totalPages; - - public List requests; - - public SagaExecutionQueryResult() { - } - - public SagaExecutionQueryResult(int pageIndex, int pageSize, int totalPages, List requests) { - this(); - this.pageIndex = pageIndex; - this.pageSize = pageSize; - this.totalPages = totalPages; - this.requests = requests; - } - } - - @JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE) - static class SagaExecution { - public long id; - public String sagaId; - public long startTime; - public String status; - public long completedTime; - - public SagaExecution() { - } - - public SagaExecution(long id, String sagaId, long startTime, long completedTime, String status) { - this(); - this.id = id; - this.sagaId = sagaId; - this.startTime = startTime; - this.completedTime = completedTime; - this.status = status; - } - } - - @JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE) - static class SagaExecutionDetail { - public Map> router; - public Map status; - public Map error; - - public SagaExecutionDetail() { - } - - public SagaExecutionDetail(Map> router, Map status, - Map error) { - this(); - this.router = router; - this.status = status; - this.error = error; - } - } -} diff --git a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaEventEntity.java b/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaEventEntity.java deleted file mode 100644 index 6be35013d..000000000 --- a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaEventEntity.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import java.util.Date; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; - -@Entity -public class SagaEventEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - private String sagaId; - private Date creationTime; - private String type; - private String contentJson; - - public SagaEventEntity() { - } - - public SagaEventEntity(String sagaId, String type, String contentJson) { - this.sagaId = sagaId; - this.type = type; - this.contentJson = contentJson; - this.creationTime = new Date(); - } - - public SagaEventEntity(long id, String sagaId, long timestamp, String type, String contentJson) { - this.id = id; - this.sagaId = sagaId; - this.creationTime = new Date(timestamp); - this.type = type; - this.contentJson = contentJson; - } - - public long id() { - return id; - } - - public String sagaId() { - return sagaId; - } - - public long creationTime() { - return creationTime.getTime(); - } - - public String type() { - return type; - } - - public String contentJson() { - return contentJson; - } - - @Override - public String toString() { - return "SagaEventEntity{" + - "id=" + id + - ", sagaId='" + sagaId + '\'' + - ", creationTime=" + creationTime + - ", type='" + type + '\'' + - ", contentJson='" + contentJson + '\'' + - '}'; - } -} diff --git a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaEventRepo.java b/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaEventRepo.java deleted file mode 100644 index 1f1132b35..000000000 --- a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaEventRepo.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import java.util.Date; -import java.util.List; - -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.PagingAndSortingRepository; - -interface SagaEventRepo extends PagingAndSortingRepository { - - // TODO: 8/21/2017 replace with hql? - @Query(value = "SELECT * FROM SagaEventEntity " - + "WHERE sagaId NOT IN (" - + " SELECT DISTINCT sagaId FROM SagaEventEntity" - + " WHERE type = 'SagaEndedEvent'" - + ")", nativeQuery = true) - List findIncompleteSagaEventsGroupBySagaId(); - - Page findByTypeAndCreationTimeBetweenOrderByIdDesc(String type, Date startTime, Date endTime, - Pageable pageable); - - SagaEventEntity findFirstByTypeAndSagaId(String type, String sagaId); - - List findBySagaId(String sagaId); -} diff --git a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaExecutionQueryService.java b/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaExecutionQueryService.java deleted file mode 100644 index 15f8cc597..000000000 --- a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaExecutionQueryService.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; - -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaStartedEvent; -import org.apache.servicecomb.saga.core.dag.GraphCycleDetectorImpl; -import org.apache.servicecomb.saga.core.dag.Node; -import org.apache.servicecomb.saga.core.dag.SingleLeafDirectedAcyclicGraph; -import org.apache.servicecomb.saga.spring.SagaController.SagaExecution; -import org.apache.servicecomb.saga.spring.SagaController.SagaExecutionDetail; -import org.apache.servicecomb.saga.spring.SagaController.SagaExecutionQueryResult; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.stereotype.Service; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.apache.servicecomb.saga.core.SagaDefinition; -import org.apache.servicecomb.saga.core.SagaEndedEvent; -import org.apache.servicecomb.saga.core.TransactionAbortedEvent; -import org.apache.servicecomb.saga.core.TransactionEndedEvent; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import org.apache.servicecomb.saga.core.dag.GraphBuilder; - -import io.servicecomb.swagger.invocation.exception.InvocationException; - -@Service -public class SagaExecutionQueryService { - private final SagaEventRepo repo; - private final FromJsonFormat fromJsonFormat; - private final SimpleDateFormat dateFormat; - - private final ObjectMapper mapper = new ObjectMapper(); - private final GraphBuilder graphBuilder = new GraphBuilder(new GraphCycleDetectorImpl<>()); - - @Autowired - public SagaExecutionQueryService(SagaEventRepo repo, FromJsonFormat fromJsonFormat) { - this.repo = repo; - this.fromJsonFormat = fromJsonFormat; - this.dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - } - - public SagaExecutionQueryResult querySagaExecution(String pageIndex, String pageSize, - String startTime, String endTime) throws ParseException { - - Date start = "NaN-NaN-NaN NaN:NaN:NaN".equals(startTime) ? new Date(0) : this.dateFormat.parse(startTime); - Date end = "NaN-NaN-NaN NaN:NaN:NaN".equals(endTime) ? new Date() : this.dateFormat.parse(endTime); - - List requests = new ArrayList<>(); - Page startEvents = repo.findByTypeAndCreationTimeBetweenOrderByIdDesc( - SagaStartedEvent.class.getSimpleName(), start, end, - new PageRequest(Integer.parseInt(pageIndex), Integer.parseInt(pageSize))); - for (SagaEventEntity event : startEvents) { - SagaEventEntity endEvent = repo - .findFirstByTypeAndSagaId(SagaEndedEvent.class.getSimpleName(), event.sagaId()); - SagaEventEntity abortedEvent = repo - .findFirstByTypeAndSagaId(TransactionAbortedEvent.class.getSimpleName(), event.sagaId()); - - requests.add(new SagaExecution( - event.id(), - event.sagaId(), - event.creationTime(), - endEvent == null ? 0 : endEvent.creationTime(), - endEvent == null ? "Running" : abortedEvent == null ? "OK" : "Failed")); - } - - return new SagaExecutionQueryResult(Integer.parseInt(pageIndex), Integer.parseInt(pageSize), - startEvents.getTotalPages(), requests); - } - - public SagaExecutionDetail querySagaExecutionDetail(String sagaId) { - SagaEventEntity[] entities = repo.findBySagaId(sagaId).toArray(new SagaEventEntity[0]); - Optional sagaStartEvent = Arrays.stream(entities) - .filter(entity -> SagaStartedEvent.class.getSimpleName().equals(entity.type())).findFirst(); - Map> router = new HashMap<>(); - Map status = new HashMap<>(); - Map error = new HashMap<>(); - if (sagaStartEvent.isPresent()) { - SagaDefinition definition = fromJsonFormat.fromJson(sagaStartEvent.get().contentJson()); - SingleLeafDirectedAcyclicGraph graph = graphBuilder - .build(definition.requests()); - loopLoadGraphNodes(router, graph.root()); - - Collection transactionAbortEvents = Arrays.stream(entities) - .filter(entity -> TransactionAbortedEvent.class.getSimpleName().equals(entity.type())).collect( - Collectors.toList()); - for (SagaEventEntity transactionAbortEvent : transactionAbortEvents) { - try { - JsonNode root = mapper.readTree(transactionAbortEvent.contentJson()); - String id = root.at("/request/id").asText(); - status.put(id, "Failed"); - error.put(id, root.at("/response/body").asText()); - } catch (IOException ex) { - throw new InvocationException(INTERNAL_SERVER_ERROR, "illegal json content"); - } - } - - Collection transactionEndEvents = Arrays.stream(entities) - .filter(entity -> TransactionEndedEvent.class.getSimpleName().equals(entity.type())).collect( - Collectors.toList()); - for (SagaEventEntity transactionEndEvent : transactionEndEvents) { - try { - JsonNode root = mapper.readTree(transactionEndEvent.contentJson()); - status.put(root.at("/request/id").asText(), "OK"); - } catch (IOException ex) { - throw new InvocationException(INTERNAL_SERVER_ERROR, "illegal json content"); - } - } - } - return new SagaExecutionDetail(router, status, error); - } - - private void loopLoadGraphNodes(Map> router, Node node) { - if (isNodeValid(node)) { - HashSet point = router.computeIfAbsent(node.value().id(), key -> new HashSet<>()); - for (Node child : node.children()) { - point.add(child.value().id()); - loopLoadGraphNodes(router, child); - } - } - } - - private boolean isNodeValid(Node node) { - return !node.children().isEmpty(); - } -} diff --git a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaRecoveryListener.java b/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaRecoveryListener.java deleted file mode 100644 index 6b6e31d3f..000000000 --- a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaRecoveryListener.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import java.lang.invoke.MethodHandles; - -import org.apache.servicecomb.saga.core.application.SagaExecutionComponent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.ApplicationListener; - -class SagaRecoveryListener implements ApplicationListener { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - @Override - public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { - log.info("Recovering pending sagas from saga log"); - applicationReadyEvent.getApplicationContext().getBean(SagaExecutionComponent.class).reanimate(); - log.info("Recovered pending sagas from saga log successfully"); - } -} diff --git a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaShutdownListener.java b/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaShutdownListener.java deleted file mode 100644 index 8ec862ec8..000000000 --- a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaShutdownListener.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - - -import org.apache.servicecomb.saga.core.application.SagaExecutionComponent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextClosedEvent; - -import java.lang.invoke.MethodHandles; - -public class SagaShutdownListener implements ApplicationListener { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - @Override - public void onApplicationEvent(ContextClosedEvent contextClosedEvent) { - try { - log.info("Stopping sagas"); - contextClosedEvent.getApplicationContext().getBean(SagaExecutionComponent.class).terminate(); - log.info("Stopped sagas successfully."); - } catch (Exception ex) { - log.error("Stopped sagas failed.", ex); - } - } -} diff --git a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaSpringApplication.java b/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaSpringApplication.java deleted file mode 100644 index 3e17c14b5..000000000 --- a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaSpringApplication.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import javax.annotation.PreDestroy; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -import kamon.Kamon; - -@SpringBootApplication -public class SagaSpringApplication { - - public static void main(String[] args) { - Kamon.start(); - SpringApplication.run(SagaSpringApplication.class, args); - } - - @PreDestroy - void shutdown() { - Kamon.shutdown(); - } -} diff --git a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaSpringConfig.java b/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaSpringConfig.java deleted file mode 100644 index d40f724f1..000000000 --- a/saga-spring/src/main/java/org/apache/servicecomb/saga/spring/SagaSpringConfig.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.saga.core.JacksonToJsonFormat; -import org.apache.servicecomb.saga.core.ToJsonFormat; -import org.apache.servicecomb.saga.core.actors.ActorBasedSagaFactory; -import org.apache.servicecomb.saga.core.application.SagaExecutionComponent; -import org.apache.servicecomb.saga.core.application.SagaFactory; -import org.apache.servicecomb.saga.core.dag.GraphBasedSagaFactory; -import org.apache.servicecomb.saga.format.ChildrenExtractor; -import org.apache.servicecomb.saga.format.JacksonFromJsonFormat; -import org.apache.servicecomb.saga.format.SagaEventFormat; -import org.apache.servicecomb.saga.transports.TransportFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import org.apache.servicecomb.saga.core.PersistentStore; -import org.apache.servicecomb.saga.core.SagaDefinition; -import org.apache.servicecomb.saga.core.application.interpreter.FromJsonFormat; -import org.apache.servicecomb.saga.format.JacksonSagaEventFormat; -import org.apache.servicecomb.saga.transports.RestTransport; - -@Configuration -class SagaSpringConfig { - - @Bean - TransportFactory transportFactory(RestTransport restTransport) { - return () -> restTransport; - } - - @Bean - FromJsonFormat fromJsonFormat(TransportFactory transportFactory) { - return new JacksonFromJsonFormat(transportFactory); - } - - @Bean - ToJsonFormat toJsonFormat() { - return new JacksonToJsonFormat(); - } - - @Bean - SagaEventFormat sagaEventFormat(TransportFactory transportFactory) { - return new JacksonSagaEventFormat(transportFactory); - } - - @Bean - PersistentStore persistentStore(SagaEventRepo repo, ToJsonFormat toJsonFormat, SagaEventFormat eventFormat) { - return new JpaPersistentStore(repo, toJsonFormat, eventFormat); - } - - @Bean - SagaExecutionQueryService queryService(SagaEventRepo repo, FromJsonFormat fromJsonFormat) { - return new SagaExecutionQueryService(repo, fromJsonFormat); - } - - @Bean - SagaExecutionComponent sagaExecutionComponent( - PersistentStore persistentStore, - ToJsonFormat format, - FromJsonFormat fromJsonFormat, - SagaFactory sagaFactory) { - - return new SagaExecutionComponent( - persistentStore, - fromJsonFormat, - format, - sagaFactory); - } - - @Bean - FromJsonFormat> childrenExtractor() { - return new ChildrenExtractor(); - } - - @ConditionalOnProperty(value = "saga.runningMode", havingValue = "graph", matchIfMissing = true) - @Bean - SagaFactory graphBasedSagaFactory( - @Value("${saga.thread.count:5}") int numberOfThreads, - @Value("${saga.retry.delay:3000}") int retryDelay, - PersistentStore persistentStore, - FromJsonFormat> childrenExtractor) { - - return new GraphBasedSagaFactory( - retryDelay, - persistentStore, - childrenExtractor, - Executors.newFixedThreadPool(numberOfThreads, sagaThreadFactory())); - } - - @ConditionalOnProperty(value = "saga.runningMode", havingValue = "actor") - @Bean - SagaFactory actorBasedSagaFactory( - @Value("${saga.retry.delay:3000}") int retryDelay, - PersistentStore persistentStore, - FromJsonFormat> childrenExtractor) { - - return new ActorBasedSagaFactory( - retryDelay, - persistentStore, - childrenExtractor); - } - - private ThreadFactory sagaThreadFactory() { - return new ThreadFactory() { - private final AtomicInteger threadCount = new AtomicInteger(); - - @Override - public Thread newThread(Runnable r) { - return new Thread(r, "saga-pool-thread-" + threadCount.incrementAndGet()); - } - }; - } -} diff --git a/saga-spring/src/main/resources/META-INF/aop.xml b/saga-spring/src/main/resources/META-INF/aop.xml deleted file mode 100644 index c48103637..000000000 --- a/saga-spring/src/main/resources/META-INF/aop.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - diff --git a/saga-spring/src/main/resources/META-INF/spring.factories b/saga-spring/src/main/resources/META-INF/spring.factories deleted file mode 100644 index ff5b14fd6..000000000 --- a/saga-spring/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,20 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -org.springframework.context.ApplicationListener=\ - org.apache.servicecomb.saga.spring.SagaRecoveryListener,\ - org.apache.servicecomb.saga.spring.SagaShutdownListener diff --git a/saga-spring/src/main/resources/application.conf b/saga-spring/src/main/resources/application.conf deleted file mode 100644 index d50e5916c..000000000 --- a/saga-spring/src/main/resources/application.conf +++ /dev/null @@ -1,88 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -############################### -# Kamon related configuration # -############################### - -kamon { - - metric { - filters { - trace.includes = ["**"] - trace-segment.includes = ["**"] - trace-segment.excludes = [] - akka-actor.includes = [] - akka-actor.excludes = ["**"] - akka-dispatcher.includes = [] - akka-dispatcher.excludes = ["**"] - } - } - - show-aspectj-missing-warning = no - - modules { - kamon-annotation { - auto-start = no - requires-aspectj = yes - } - - kamon-log-reporter { - auto-start = no - requires-aspectj = no - } - - kamon-statsd { - auto-start = no - requires-aspectj = no - } - } - - statsd { - # Hostname and port in which your StatsD is running. Remember that StatsD packets are sent using UDP and - # setting unreachable hosts and/or not open ports wont be warned by the Kamon, your data wont go anywhere. - hostname = "localhost" - port = 8125 - - # Interval between metrics data flushes to StatsD. It's value must be equal or greater than the - # kamon.metrics.tick-interval setting. - flush-interval = 10 second - - # Subscription patterns used to select which metrics will be pushed to StatsD. Note that first, metrics - # collection for your desired entities must be activated under the kamon.metrics.filters settings. - includes { - actor = [] - trace = ["*"] - trace-segment = ["*"] - dispatcher = [] - } - - subscriptions { - histogram = ["**"] - min-max-counter = ["**"] - gauge = ["**"] - counter = ["**"] - trace = ["**"] - trace-segment = ["**"] - akka-actor = [] - akka-dispatcher = [] - akka-router = [] - system-metric = [] - http-server = [] - } - } -} diff --git a/saga-spring/src/main/resources/application.yaml b/saga-spring/src/main/resources/application.yaml deleted file mode 100644 index 6ed0d9d5b..000000000 --- a/saga-spring/src/main/resources/application.yaml +++ /dev/null @@ -1,30 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -spring: - profiles: prd - datasource: - username: saga - password: password - url: jdbc:postgresql://postgres.servicecomb.io:5432/saga?useSSL=false - platform: postgresql -# continue-on-error: true - -saga: - thread: - count: 32 - retry: - delay: 3000 diff --git a/saga-spring/src/main/resources/log4j2.xml b/saga-spring/src/main/resources/log4j2.xml deleted file mode 100644 index cae04cb93..000000000 --- a/saga-spring/src/main/resources/log4j2.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/saga-spring/src/main/resources/schema-postgresql.sql b/saga-spring/src/main/resources/schema-postgresql.sql deleted file mode 100644 index 7a2cd1fe0..000000000 --- a/saga-spring/src/main/resources/schema-postgresql.sql +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -CREATE TABLE IF NOT EXISTS SagaEventEntity ( - id BIGSERIAL PRIMARY KEY, - sagaId varchar(36) NOT NULL, - creationTime timestamp(6) NOT NULL DEFAULT CURRENT_DATE, - type varchar(50) NOT NULL, - contentJson TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS running_sagas_index ON SagaEventEntity (sagaId, type); diff --git a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/ActorBasedSagaSpringApplicationTest.java b/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/ActorBasedSagaSpringApplicationTest.java deleted file mode 100644 index f88267237..000000000 --- a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/ActorBasedSagaSpringApplicationTest.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest(classes = SagaSpringApplication.class, properties = "saga.runningMode=actor") -public class ActorBasedSagaSpringApplicationTest extends SagaSpringApplicationTestBase { - -} diff --git a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/GraphBasedSagaSpringApplicationTest.java b/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/GraphBasedSagaSpringApplicationTest.java deleted file mode 100644 index f5fddcb85..000000000 --- a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/GraphBasedSagaSpringApplicationTest.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest(classes = SagaSpringApplication.class) -public class GraphBasedSagaSpringApplicationTest extends SagaSpringApplicationTestBase { - -} diff --git a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/GreetingController.java b/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/GreetingController.java deleted file mode 100644 index 0710c0183..000000000 --- a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/GreetingController.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; - -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestMapping; - -import io.servicecomb.provider.rest.common.RestSchema; - -@Controller -@RequestMapping("/rest") -@RestSchema(schemaId = "greeting-rest-endpoint") -public class GreetingController { - - @RequestMapping(value = "/usableResource", method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE) - public ResponseEntity postUsableResource( - @RequestAttribute(name = "hello") String who, - @RequestAttribute(name = "response") String response) { - - return ResponseEntity.ok("hello " + who + ", with response " + response); - } -} diff --git a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaRecoveryTest.java b/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaRecoveryTest.java deleted file mode 100644 index 0d1e9c5ad..000000000 --- a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaRecoveryTest.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.containing; -import static com.github.tomakehurst.wiremock.client.WireMock.delete; -import static com.github.tomakehurst.wiremock.client.WireMock.deleteRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.exactly; -import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static java.util.Collections.singletonMap; - -import org.apache.servicecomb.saga.core.NoOpSagaRequest; -import org.apache.servicecomb.saga.core.SagaRequestImpl; -import org.apache.servicecomb.saga.core.SagaStartedEvent; -import org.apache.servicecomb.saga.core.ToJsonFormat; -import org.apache.servicecomb.saga.format.JacksonRestCompensation; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.context.annotation.Profile; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; - -import com.github.tomakehurst.wiremock.junit.WireMockRule; - -import org.apache.servicecomb.saga.core.PersistentStore; -import org.apache.servicecomb.saga.core.SagaEndedEvent; -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.SuccessfulSagaResponse; -import org.apache.servicecomb.saga.core.TransactionAbortedEvent; -import org.apache.servicecomb.saga.core.TransactionCompensatedEvent; -import org.apache.servicecomb.saga.core.TransactionEndedEvent; -import org.apache.servicecomb.saga.core.TransactionStartedEvent; -import org.apache.servicecomb.saga.format.JacksonFallback; -import org.apache.servicecomb.saga.format.JacksonRestTransaction; -import org.apache.servicecomb.saga.format.SagaEventFormat; -import org.apache.servicecomb.saga.spring.SagaRecoveryTest.EventPopulatingConfig; -import wiremock.org.apache.http.HttpStatus; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = {SagaSpringApplication.class, EventPopulatingConfig.class}) -@ActiveProfiles("recovery-test") -public class SagaRecoveryTest { - - @ClassRule - public static final WireMockRule wireMockRule = new WireMockRule(8090); - - private static String request(final String name) { - return " {\n" - + " \"id\": \"request-" + name + "\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"localhost:8090\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/" + name + "\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"foo\": \"" + name + "\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/" + name + "\",\n" - + " \"params\": {\n" - + " \"query\": {\n" - + " \"bar\": \"" + name + "\"\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n"; - } - - private static final String requestY = "[\n" - + request("yyy1") - + "," - + request("yyy2") - + "," - + request("yyy3") - + "]\n"; - - private static final String sagaY = "{\"policy\": \"ForwardRecovery\",\"requests\": " + requestY + "}"; - - @BeforeClass - public static void setUp() throws Exception { - stubFor(delete(urlPathEqualTo("/rest/yyy1")) - .withQueryParam("bar", containing("yyy1")) - .willReturn( - aResponse() - .withStatus(HttpStatus.SC_OK) - .withBody("success"))); - } - - @Test - public void recoverIncompleteSagasFromSagaLog() throws Exception { - verify(exactly(0), postRequestedFor(urlPathEqualTo("/rest/xxx"))); - - verify(exactly(0), postRequestedFor(urlPathEqualTo("/rest/yyy1"))); - verify(exactly(1), deleteRequestedFor(urlPathEqualTo("/rest/yyy1"))); - - verify(exactly(0), postRequestedFor(urlPathEqualTo("/rest/yyy2"))); - verify(exactly(0), deleteRequestedFor(urlPathEqualTo("/rest/yyy2"))); - - verify(exactly(0), postRequestedFor(urlPathEqualTo("/rest/yyy3"))); - verify(exactly(0), deleteRequestedFor(urlPathEqualTo("/rest/yyy3"))); - } - - @Profile("recovery-test") - @Configuration - static class EventPopulatingConfig { - - private static final String DONT_CARE = "{}"; - - private final SagaRequest request1 = sagaRequest("yyy1"); - private final SagaRequest request2 = sagaRequest("yyy2"); - private final SagaRequest request3 = sagaRequest("yyy3"); - - private final SagaResponse response1 = new SuccessfulSagaResponse("succeeded, yyy1"); - private final SagaResponse response2 = new SuccessfulSagaResponse("succeeded, yyy2"); - - @Primary - @Bean - PersistentStore persistentStore(SagaEventRepo repo, ToJsonFormat toJsonFormat, SagaEventFormat sagaEventFormat) { - repo.save(new SagaEventEntity("xxx", SagaStartedEvent.class.getSimpleName(), DONT_CARE)); - repo.save(new SagaEventEntity("xxx", TransactionStartedEvent.class.getSimpleName(), DONT_CARE)); - repo.save(new SagaEventEntity("xxx", TransactionEndedEvent.class.getSimpleName(), DONT_CARE)); - repo.save(new SagaEventEntity("xxx", SagaEndedEvent.class.getSimpleName(), DONT_CARE)); - - PersistentStore store = new JpaPersistentStore(repo, toJsonFormat, sagaEventFormat); - - store.offer(new SagaStartedEvent("yyy", sagaY, NoOpSagaRequest.SAGA_START_REQUEST)); - store.offer(new TransactionStartedEvent("yyy", request1)); - store.offer(new TransactionEndedEvent("yyy", request1, response1)); - - store.offer(new TransactionStartedEvent("yyy", request2)); - store.offer(new TransactionEndedEvent("yyy", request2, response2)); - - store.offer(new TransactionStartedEvent("yyy", request3)); - store.offer(new TransactionAbortedEvent("yyy", request3, new RuntimeException("oops"))); - - store.offer(new TransactionCompensatedEvent("yyy", request2, response2)); - - return store; - } - - private SagaRequestImpl sagaRequest(final String name) { - return new SagaRequestImpl( - "request-" + name, - "localhost:8080", - "rest", - new JacksonRestTransaction("/rest/" + name, "post", singletonMap("query", singletonMap("foo", name))), - new JacksonRestCompensation("rest/" + name, "delete", singletonMap("query", singletonMap("bar", name))), - JacksonFallback.NOP_TRANSPORT_AWARE_FALLBACK); - } - } -} diff --git a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaServiceDiscoveryTest.java b/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaServiceDiscoveryTest.java deleted file mode 100644 index 7ca683c13..000000000 --- a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaServiceDiscoveryTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import static io.restassured.RestAssured.given; -import static io.restassured.http.ContentType.TEXT; -import static io.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; - -import org.apache.servicecomb.saga.core.TransactionEndedEvent; - -@SuppressWarnings("unchecked") -@RunWith(SpringRunner.class) -@SpringBootTest(classes = SagaSpringApplication.class) -@ActiveProfiles("servicecomb") -public class SagaServiceDiscoveryTest { - - private static final String requests = "[\n" - + " {\n" - + " \"id\": \"request-aaa\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"saga-service\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/usableResource\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"hello\": \"world\"\n" - + " }" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/usableResource\",\n" - + " \"params\": {\n" - + " \"query\": {\n" - + " \"foo\": \"bar\"\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + "]\n"; - - private static final String sagaDefinition = "{\"policy\": \"ForwardRecovery\",\"requests\": " + requests + "}"; - - @Autowired - private SagaEventRepo sagaEventRepo; - - - @BeforeClass - public static void setUpClass() throws Exception { - setUpLocalRegistry(); - } - - private static void setUpLocalRegistry() { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - URL resource = loader.getResource("registry.yaml"); - System.setProperty(LOCAL_REGISTRY_FILE_KEY, resource.getPath()); - } - - @Test - public void processRequestByServiceDiscovery() throws Exception { - given() - .contentType(TEXT) - .body(sagaDefinition) - .when() - .post("http://localhost:8080/requests") - .then() - .statusCode(200) - .body(is("success")); - - List events = new ArrayList<>(); - sagaEventRepo.findAll().forEach(events::add); - - Optional eventEntity = events.stream() - .filter(entity -> entity.type().equals(TransactionEndedEvent.class.getSimpleName())) - .findFirst(); - - assertThat(eventEntity.isPresent(), is(true)); - assertThat(eventEntity.get().contentJson(), containsString("hello world, with response {}")); - } - -} diff --git a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaSpringApplicationTestBase.java b/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaSpringApplicationTestBase.java deleted file mode 100644 index 655446958..000000000 --- a/saga-spring/src/test/java/org/apache/servicecomb/saga/spring/SagaSpringApplicationTestBase.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.spring; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.containing; -import static com.github.tomakehurst.wiremock.client.WireMock.exactly; -import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.resetAllRequests; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.assertThat; -import static org.springframework.http.MediaType.TEXT_PLAIN; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.net.URLEncoder; - -import org.apache.servicecomb.saga.spring.SagaController.SagaExecutionDetail; -import org.apache.servicecomb.saga.spring.SagaController.SagaExecutionQueryResult; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.junit.WireMockRule; - -import wiremock.org.apache.http.HttpStatus; - -@SuppressWarnings("unchecked") -@RunWith(SpringRunner.class) -@AutoConfigureMockMvc -public class SagaSpringApplicationTestBase { - - private static final ObjectMapper mapper = new ObjectMapper(); - - @ClassRule - public static final WireMockRule wireMockRule = new WireMockRule(8090); - - private static final String requests = "[\n" - + " {\n" - + " \"id\": \"request-aaa\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"localhost:8090\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/as\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"foo\": \"as\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/as\",\n" - + " \"params\": {\n" - + " \"query\": {\n" - + " \"bar\": \"as\"\n" - + " }\n" - + " }\n" - + " }\n" - + " },\n" - + " {\n" - + " \"id\": \"request-bbb\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"localhost:8090\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/as\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"foo\": \"as\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/as\",\n" - + " \"params\": {\n" - + " \"query\": {\n" - + " \"bar\": \"as\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"parents\": [\"request-aaa\"]\n" - + " }\n" - + "]\n"; - - private static final String failRequests = "[\n" - + " {\n" - + " \"id\": \"request-aaa\",\n" - + " \"type\": \"rest\",\n" - + " \"serviceName\": \"localhost:8090\",\n" - + " \"transaction\": {\n" - + " \"method\": \"post\",\n" - + " \"path\": \"/rest/bs\",\n" - + " \"params\": {\n" - + " \"form\": {\n" - + " \"foo\": \"bs\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"compensation\": {\n" - + " \"method\": \"delete\",\n" - + " \"path\": \"/rest/bs\",\n" - + " \"params\": {\n" - + " \"query\": {\n" - + " \"bar\": \"bs\"\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + "]\n"; - - private static final String sagaDefinition = "{\"policy\": \"ForwardRecovery\",\"requests\": " + requests + "}"; - private static final String sagaFailDefinition = - "{\"policy\": \"BackwardRecovery\",\"requests\": " + failRequests + "}"; - - @Autowired - private MockMvc mockMvc; - - @Autowired - private SagaEventRepo sagaEventRepo; - - @BeforeClass - public static void setUp() throws Exception { - stubFor(WireMock.post(urlPathEqualTo("/rest/as")) - .withRequestBody(containing("foo=as&response=" + URLEncoder.encode("{}", "UTF-8"))) - .willReturn( - aResponse() - .withStatus(HttpStatus.SC_OK) - .withBody("{\n" - + " \"body\": \"success\",\n" - + " \"sagaChildren\": [\"none\"]\n" - + "}"))); - - stubFor(WireMock.post(urlPathEqualTo("/rest/bs")) - .withRequestBody(containing("foo=bs")) - .willReturn( - aResponse() - .withStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR) - .withBody("process failed"))); - } - - @Before - public void tearUp() { - resetAllRequests(); - sagaEventRepo.deleteAll(); - } - - @Test - public void testBadFormatRequest() throws Exception { - try { - mockMvc.perform( - post("/requests/") - .contentType(TEXT_PLAIN) - .content("xxxx")) - .andExpect(status().is(HttpStatus.SC_BAD_REQUEST)) - .andExpect(content().string(containsString("illegal request content"))); - } catch (org.springframework.web.util.NestedServletException ex) { - assertThat(ex.getMessage(), containsString("Failed to interpret JSON xxxx")); - } - } - - @Test - public void testFailedRequest() throws Exception { - try { - mockMvc.perform( - post("/requests/") - .contentType(TEXT_PLAIN) - .content(sagaFailDefinition)) - .andExpect(status().is(HttpStatus.SC_INTERNAL_SERVER_ERROR)) - .andExpect(content().string(containsString("transaction failed"))); - } catch (org.springframework.web.util.NestedServletException ex) { - assertThat(ex.getMessage(), containsString( - "The remote service returned with status code 500, reason Server Error")); - } - - MvcResult resultJson = mockMvc.perform(get("/requests") - .param("pageIndex", "0") - .param("pageSize", "10") - .param("startTime", "NaN-NaN-NaN NaN:NaN:NaN") - .param("endTime", "NaN-NaN-NaN NaN:NaN:NaN")) - .andExpect(status().isOk()).andReturn(); - SagaExecutionQueryResult result = mapper - .readValue(resultJson.getResponse().getContentAsString(), SagaExecutionQueryResult.class); - assertThat(result.requests.size(), is(1)); - - String sagaId = result.requests.get(0).sagaId; - - MvcResult detailJson = mockMvc.perform(get("/requests/" + sagaId)).andExpect(status().isOk()) - .andReturn(); - SagaExecutionDetail executionDetail = mapper - .readValue(detailJson.getResponse().getContentAsString(), SagaExecutionDetail.class); - - assertThat(executionDetail.router.keySet(), containsInAnyOrder("saga-start", "request-aaa")); - assertThat(executionDetail.status.get("request-aaa"), is("Failed")); - assertThat(executionDetail.error.size(), is(1)); - } - - @Test - public void processRequestByRest() throws Exception { - mockMvc.perform( - post("/requests/") - .contentType(TEXT_PLAIN) - .content(sagaDefinition)) - .andExpect(status().isOk()); - - verify(exactly(1), postRequestedFor(urlPathEqualTo("/rest/as"))); - - Iterable events = sagaEventRepo.findAll(); - - assertThat(events, contains( - eventWith(1L, "SagaStartedEvent"), - eventWith(2L, "TransactionStartedEvent"), - eventWith(3L, "TransactionEndedEvent"), - eventWith(4L, "SagaEndedEvent") - )); - - MvcResult resultJson = mockMvc.perform(get("/requests") - .param("pageIndex", "0") - .param("pageSize", "10") - .param("startTime", "NaN-NaN-NaN NaN:NaN:NaN") - .param("endTime", "NaN-NaN-NaN NaN:NaN:NaN")) - .andExpect(status().isOk()).andReturn(); - SagaExecutionQueryResult result = mapper - .readValue(resultJson.getResponse().getContentAsString(), SagaExecutionQueryResult.class); - assertThat(result.requests.size(), is(1)); - - String sagaId = result.requests.get(0).sagaId; - - MvcResult detailJson = mockMvc.perform(get("/requests/" + sagaId)).andExpect(status().isOk()) - .andReturn(); - SagaExecutionDetail executionDetail = mapper - .readValue(detailJson.getResponse().getContentAsString(), SagaExecutionDetail.class); - - assertThat(executionDetail.router.keySet(), containsInAnyOrder("saga-start", "request-bbb", "request-aaa")); - assertThat(executionDetail.status.get("request-aaa"), is("OK")); - assertThat(executionDetail.error.size(), is(0)); - } - - @Test - public void queryRequestsWithBadParameter() throws Exception { - try { - mockMvc.perform(get("/requests") - .param("pageIndex", "xxx") - .param("pageSize", "xxx") - .param("startTime", "NaN-NaN-NaN NaN:NaN:NaN") - .param("endTime", "NaN-NaN-NaN NaN:NaN:NaN")) - .andExpect(status().is(HttpStatus.SC_BAD_REQUEST)); - } catch (org.springframework.web.util.NestedServletException ex) { - assertThat(ex.getMessage(), containsString("illegal request content")); - } - - try { - mockMvc.perform(get("/requests") - .param("pageIndex", "0") - .param("pageSize", "10") - .param("startTime", "x0") - .param("endTime", "x1")) - .andExpect(status().is(HttpStatus.SC_BAD_REQUEST)); - } catch (org.springframework.web.util.NestedServletException ex) { - assertThat(ex.getMessage(), containsString("illegal request content")); - } - } - - @Test - public void queryRequestsWithNANParameter() throws Exception { - mockMvc.perform( - post("/requests/") - .contentType(TEXT_PLAIN) - .content(sagaDefinition)) - .andExpect(status().isOk()); - - MvcResult resultJson = mockMvc.perform(get("/requests") - .param("pageIndex", "0") - .param("pageSize", "10") - .param("startTime", "NaN-NaN-NaN NaN:NaN:NaN") - .param("endTime", "NaN-NaN-NaN NaN:NaN:NaN")) - .andExpect(status().is(HttpStatus.SC_OK)).andReturn(); - SagaExecutionQueryResult result = mapper - .readValue(resultJson.getResponse().getContentAsString(), SagaExecutionQueryResult.class); - assertThat(result.requests.size(), is(1)); - - resultJson = mockMvc.perform(get("/requests") - .param("pageIndex", "0") - .param("pageSize", "10") - .param("startTime", "2000-1-1 00:00:00") - .param("endTime", "NaN-NaN-NaN NaN:NaN:NaN")) - .andExpect(status().is(HttpStatus.SC_OK)).andReturn(); - result = mapper - .readValue(resultJson.getResponse().getContentAsString(), SagaExecutionQueryResult.class); - assertThat(result.requests.size(), is(1)); - - resultJson = mockMvc.perform(get("/requests") - .param("pageIndex", "0") - .param("pageSize", "10") - .param("startTime", "NaN-NaN-NaN NaN:NaN:NaN") - .param("endTime", "9999-12-31 12:59:59")) - .andExpect(status().is(HttpStatus.SC_OK)).andReturn(); - result = mapper - .readValue(resultJson.getResponse().getContentAsString(), SagaExecutionQueryResult.class); - assertThat(result.requests.size(), is(1)); - - try { - mockMvc.perform(get("/requests") - .param("pageIndex", "0") - .param("pageSize", "10") - .param("startTime", "9999-12-31 12:59:59") - .param("endTime", "2000-1-1 00:00:00")) - .andExpect(status().is(HttpStatus.SC_BAD_REQUEST)); - } catch (org.springframework.web.util.NestedServletException ex) { - assertThat(ex.getMessage(), containsString("illegal request content")); - } - } - - @Test - public void allEvents() throws Exception { - mockMvc.perform( - post("/requests/") - .contentType(TEXT_PLAIN) - .content(sagaDefinition)) - .andExpect(status().isOk()); - mockMvc.perform(get("/events")).andExpect(status().isOk()) - .andExpect(content().string(containsString("SagaStartedEvent"))) - .andExpect(content().string(containsString("request-aaa"))) - .andExpect(content().string(containsString("request-bbb"))) - .andExpect(content().string(containsString("SagaEndedEvent"))); - } - - - private Matcher eventWith( - long eventId, - String type) { - - return new TypeSafeMatcher() { - @Override - protected boolean matchesSafely(SagaEventEntity event) { - return eventId == event.id() && event.type().equals(type); - } - - @Override - protected void describeMismatchSafely(SagaEventEntity item, Description mismatchDescription) { - mismatchDescription.appendText(item.toString()); - } - - @Override - public void describeTo(Description description) { - description.appendText( - "SagaEventEntity {" - + "id=" + eventId - + ", type=" + type); - } - }; - } -} diff --git a/saga-spring/src/test/resources/data.sql b/saga-spring/src/test/resources/data.sql deleted file mode 100644 index 5cdb7d92f..000000000 --- a/saga-spring/src/test/resources/data.sql +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -DROP TABLE IF EXISTS SagaEventEntity; - -CREATE TABLE `SagaEventEntity` ( - `id` bigint NOT NULL AUTO_INCREMENT, - `sagaId` varchar(36) NOT NULL, - `creationTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `type` varchar(50) NOT NULL, - `contentJson` clob NOT NULL DEFAULT '{}', - PRIMARY KEY (`id`) -) DEFAULT CHARSET=utf8; - - CREATE INDEX running_sagas_index ON sagaEventEntity(sagaId, type); diff --git a/saga-spring/src/test/resources/log4j2-test.xml b/saga-spring/src/test/resources/log4j2-test.xml deleted file mode 100644 index 58924c686..000000000 --- a/saga-spring/src/test/resources/log4j2-test.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/saga-spring/src/test/resources/registry.yaml b/saga-spring/src/test/resources/registry.yaml deleted file mode 100644 index 82752b441..000000000 --- a/saga-spring/src/test/resources/registry.yaml +++ /dev/null @@ -1,23 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -saga-service: - - id: "001" - version: "0.0.1" - appid: saga - instances: - - endpoints: - - rest://127.0.0.1:8080?sslEnabled=false diff --git a/saga-web/pom.xml b/saga-web/pom.xml deleted file mode 100644 index 94b1ec065..000000000 --- a/saga-web/pom.xml +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - saga - org.apache.servicecomb.saga - 0.0.3-SNAPSHOT - - 4.0.0 - - saga-web - Saga::Web - - - - - org.apache.commons - commons-lang3 - 3.6 - - - io.servicecomb - spring-boot-starter-provider - ${java.chassis.version} - - - com.google.code.findbugs - annotations - - - - - io.servicecomb - spring-boot-starter-discovery - ${java.chassis.version} - - - com.google.code.findbugs - annotations - - - - - io.servicecomb - java-chassis-dependencies - ${java.chassis.version} - pom - import - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - - - - org.springframework.boot - spring-boot-starter - - - io.servicecomb - spring-boot-starter-discovery - - - io.servicecomb - spring-boot-starter-servicecomb - - - io.servicecomb - spring-cloud-zuul - - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - - diff --git a/saga-web/src/main/java/org/apache/servicecomb/saga/web/SagaWebApplication.java b/saga-web/src/main/java/org/apache/servicecomb/saga/web/SagaWebApplication.java deleted file mode 100644 index a095d6844..000000000 --- a/saga-web/src/main/java/org/apache/servicecomb/saga/web/SagaWebApplication.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.web; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.zuul.EnableZuulProxy; - -import io.servicecomb.springboot.starter.provider.EnableServiceComb; - -@SpringBootApplication -@EnableZuulProxy -@EnableServiceComb -public class SagaWebApplication { - - public static void main(String[] args) { - SpringApplication.run(SagaWebApplication.class, args); - } -} diff --git a/saga-web/src/main/resources/application.yaml b/saga-web/src/main/resources/application.yaml deleted file mode 100644 index 3bb08342b..000000000 --- a/saga-web/src/main/resources/application.yaml +++ /dev/null @@ -1,29 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -zuul: - routes: - saga-service: - serviceId: saga-service - -# disable netflix eureka since it's not used for service discovery -ribbon: - eureka: - enabled: false - -server: - port: 8888 \ No newline at end of file diff --git a/saga-web/src/main/resources/microservice.yaml b/saga-web/src/main/resources/microservice.yaml deleted file mode 100644 index 399fd0288..000000000 --- a/saga-web/src/main/resources/microservice.yaml +++ /dev/null @@ -1,31 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# all interconnected microservices must belong to an application wth the same ID -APPLICATION_ID: saga -service_description: -# name of the declaring microservice - name: saga-web - version: 0.0.1 -cse: - service: - registry: - address: http://sc.servicecomb.io:30100 - -servicecomb: - tracing: - enabled: false diff --git a/saga-web/src/main/resources/static/css/request.css b/saga-web/src/main/resources/static/css/request.css deleted file mode 100644 index a7169f0af..000000000 --- a/saga-web/src/main/resources/static/css/request.css +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -.loading, -.loading::after { - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - -webkit-transform: translate(-50%, -50%); -} - -.loading, -.loading span { - width: 62px; - height: 62px; - border-radius: 62px; -} - -.loading { - border: 5px solid #d0cecc; -} - -.loading span { - display: block; - transform: rotate(0); - -webkit-transform: rotate(0); - -webkit-animation: loading 600ms linear infinite; - animation: loading 600ms linear infinite; - background-size: 17px 8px; - background-position: 31px 1px; -} - -.loading::after { - content: "loading"; - display: block; - width: 50px; - height: 50px; - line-height: 50px; - text-align: center; - font-style: italic; - color: #fff; - font-size: 12px; - border-radius: 50px; - background: #d0cecc; -} - -.loading-data img { - width: 100%; - max-width: 100%; - background-size: cover; -} diff --git a/saga-web/src/main/resources/static/css/style.css b/saga-web/src/main/resources/static/css/style.css deleted file mode 100644 index b1b67769d..000000000 --- a/saga-web/src/main/resources/static/css/style.css +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -ul#nav { - width: 100%; - height: 30px; - background: #00A2CA; - margin: 0 auto -} - -ul#nav li { - display: inline; - height: 30px -} - -ul#nav li a { - display: inline-block; - padding: 0 20px; - height: 30px; - line-height: 30px; - color: #FFF; - font-size: 16px -} - -ul#nav li a:hover { - background: #0095BB -} \ No newline at end of file diff --git a/saga-web/src/main/resources/static/detail.html b/saga-web/src/main/resources/static/detail.html deleted file mode 100755 index ef7cbe08f..000000000 --- a/saga-web/src/main/resources/static/detail.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - Detail - - - - - - -
- - diff --git a/saga-web/src/main/resources/static/index.html b/saga-web/src/main/resources/static/index.html deleted file mode 100644 index 8dd887776..000000000 --- a/saga-web/src/main/resources/static/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - Saga Web - - - - - - - diff --git a/saga-web/src/main/resources/static/js/date.js b/saga-web/src/main/resources/static/js/date.js deleted file mode 100644 index 83f0b5c86..000000000 --- a/saga-web/src/main/resources/static/js/date.js +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var cal; -var isFocus = false; // 是否为焦点 -function SetDate(obj, strFormat) { - - var date = new Date(); - var by = date.getFullYear() - 50; // 最小值 → 50年前 - var ey = date.getFullYear() + 20; // 最大值 → 20年后 - // 初始化为中文版,1为英文版 - cal = (cal == null) ? new Calendar(by, ey, 1, strFormat) - : (cal.dateFormatStyle == strFormat ? cal : new Calendar(by, ey, 1, - strFormat)); - cal.show(obj); -} - -/**/ -/* 返回日期 */ -String.prototype.toDate = function (style) { - var y = this.substring(style.indexOf('y'), style.lastIndexOf('y') + 1);// 年 - var m = this.substring(style.indexOf('M'), style.lastIndexOf('M') + 1);// 月 - var d = this.substring(style.indexOf('d'), style.lastIndexOf('d') + 1);// 日 - var h = this.substring(style.indexOf('h'), style.lastIndexOf('h') + 1);// 时 - var i = this.substring(style.indexOf('m'), style.lastIndexOf('m') + 1);// 分 - var s = this.substring(style.indexOf('s'), style.lastIndexOf('s') + 1);// 秒 - if (isNaN(y)) { - y = new Date().getFullYear(); - } - if (isNaN(m)) { - m = new Date().getMonth(); - } - if (isNaN(d)) { - d = new Date().getDate(); - } - if (isNaN(h)) { - h = new Date().getHours(); - } - if (isNaN(i)) { - i = new Date().getMinutes(); - } - if (isNaN(s)) { - s = new Date().getSeconds(); - } - var dt; - eval("dt = new Date('" + y + "', '" + (m - 1) + "','" + d + "','" + h - + "','" + i + "','" + s + "')"); - return dt; -} -/**/ -/* 格式化日期 */ -Date.prototype.format = function (style) { - var o = { - "M+": this.getMonth() + 1, // month - "d+": this.getDate(), // day - "h+": this.getHours(), // hour - "m+": this.getMinutes(), // minute - "s+": this.getSeconds(), // second - "w+": "天一二三四五六".charAt(this.getDay()), // week - "q+": Math.floor((this.getMonth() + 3) / 3), // quarter - "S": this.getMilliseconds() - // millisecond - } - if (/(y+)/.test(style)) { - style = style.replace(RegExp.$1, (this.getFullYear() + "") - .substr(4 - RegExp.$1.length)); - } - for (var k in o) { - if (new RegExp("(" + k + ")").test(style)) { - style = style.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] - : ("00" + o[k]).substr(("" + o[k]).length)); - } - } - return style; -}; - -/**/ - -/* - * 日历类 @param beginYear 1990 @param endYear 2010 @param lang 0(中文)|1(英语) - * 可自由扩充 @param dateFormatStyle "yyyy-MM-dd"; - */ -function Calendar(beginYear, endYear, lang, dateFormatStyle) { - this.beginYear = 1990; - this.endYear = 2010; - this.lang = 0; // 0(中文) | 1(英文) - this.dateFormatStyle = "yyyy-MM-dd"; - - if (beginYear != null && endYear != null) { - this.beginYear = beginYear; - this.endYear = endYear; - } - if (lang != null) { - this.lang = lang - } - - if (dateFormatStyle != null) { - this.dateFormatStyle = dateFormatStyle - } - - this.dateControl = null; - this.panel = this.getElementById("calendarPanel"); - this.container = this.getElementById("ContainerPanel"); - this.form = null; - - this.date = new Date(); - this.year = this.date.getFullYear(); - this.month = this.date.getMonth(); - - this.colors = { - "cur_word": "#FFFFFF", // 当日日期文字颜色 - "cur_bg": "#83A6F4", // 当日日期单元格背影色 - "sel_bg": "#FFCCCC", // 已被选择的日期单元格背影色 - "sun_word": "#FF0000", // 星期天文字颜色 - "sat_word": "#0000FF", // 星期六文字颜色 - "td_word_light": "#333333", // 单元格文字颜色 - "td_word_dark": "#CCCCCC", // 单元格文字暗色 - "td_bg_out": "#EFEFEF", // 单元格背影色 - "td_bg_over": "#FFCC00", // 单元格背影色 - "tr_word": "#FFFFFF", // 日历头文字颜色 - "tr_bg": "#666666", // 日历头背影色 - "input_border": "#CCCCCC", // input控件的边框颜色 - "input_bg": "#EFEFEF" // input控件的背影色 - } - - this.draw(); - this.bindYear(); - this.bindMonth(); - this.changeSelect(); - this.bindData(); -} - -/**/ -/* - * 日历类属性(语言包,可自由扩展) - */ -Calendar.language = { - "year": [[""], [""]], - "months": [ - ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", - "十一月", "十二月"], - ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", - "OCT", "NOV", "DEC"]], - "weeks": [["日", "一", "二", "三", "四", "五", "六"], - ["SUN", "MON", "TUR", "WED", "THU", "FRI", "SAT"]], - "abort": [["时间"], ["TIME"]], - "clear": [["清空"], ["CLS"]], - "today": [["今天"], ["TODAY"]], - "close": [["关闭"], ["CLOSE"]] -} - -Calendar.prototype.draw = function () { - calendar = this; - - var mvAry = []; - mvAry[mvAry.length] = '
'; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = '
'; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - for (var i = 0; i < 7; i++) { - mvAry[mvAry.length] = ' '; - } - mvAry[mvAry.length] = ' '; - for (var i = 0; i < 6; i++) { - mvAry[mvAry.length] = ' '; - for (var j = 0; j < 7; j++) { - if (j == 0) { - mvAry[mvAry.length] = ' '; - } else if (j == 6) { - mvAry[mvAry.length] = ' '; - } else { - mvAry[mvAry.length] = ' '; - } - } - mvAry[mvAry.length] = ' '; - } - - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = ' '; - mvAry[mvAry.length] = '
' - + Calendar.language["weeks"][this.lang][i] + '
' - + Calendar.language["abort"][this.lang] + ''; - mvAry[mvAry.length] = ':'; - mvAry[mvAry.length] = ':'; - mvAry[mvAry.length] = '
'; - mvAry[mvAry.length] = '
'; - this.panel.innerHTML = mvAry.join(""); - - var obj = this.getElementById("prevMonth"); - obj.onclick = function () { - calendar.goPrevMonth(calendar); - } - obj.onblur = function () { - calendar.onblur(); - } - this.prevMonth = obj; - - obj = this.getElementById("nextMonth"); - obj.onclick = function () { - calendar.goNextMonth(calendar); - } - obj.onblur = function () { - calendar.onblur(); - } - this.nextMonth = obj; - - obj = this.getElementById("calendarClear"); - obj.onclick = function () { - calendar.dateControl.value = ""; - calendar.hide(); - } - this.calendarClear = obj; - - obj = this.getElementById("calendarClose"); - obj.onclick = function () { - calendar.hide(); - } - this.calendarClose = obj; - - obj = this.getElementById("calendarYear"); - obj.onchange = function () { - calendar.update(calendar); - } - obj.onblur = function () { - calendar.onblur(); - } - this.calendarYear = obj; - - obj = this.getElementById("calendarMonth"); - with (obj) { - onchange = function () { - calendar.update(calendar); - } - onblur = function () { - calendar.onblur(); - } - } - this.calendarMonth = obj; - - obj = this.getElementById("calendarHour"); - with (obj) { - length = 0; - for (var i = 0; i < 24; i++) { - if (i < 10) { - options[length] = new Option("0" + i, "0" + i); - } else { - options[length] = new Option(i, i); - } - } - } - this.calendarHour = obj; - - obj = this.getElementById("calendarMinute"); - with (obj) { - length = 0; - for (var i = 0; i < 60; i++) { - if (i < 10) { - options[length] = new Option("0" + i, "0" + i); - } else { - options[length] = new Option(i, i); - } - } - } - this.calendarMinute = obj; - - obj = this.getElementById("calendarSecond"); - with (obj) { - length = 0; - for (var i = 0; i < 60; i++) { - if (i < 10) { - options[length] = new Option("0" + i, "0" + i); - } else { - options[length] = new Option(i, i); - } - } - } - this.calendarSecond = obj; - - obj = this.getElementById("calendarToday"); - obj.onclick = function () { - var today = new Date(); - calendar.date = today; - calendar.year = today.getFullYear(); - calendar.month = today.getMonth(); - calendar.changeSelect(); - calendar.bindData(); - calendar.dateControl.value = today.format(calendar.dateFormatStyle); - calendar.hide(); - } - this.calendarToday = obj; -} - -// 年份下拉框绑定数据 -Calendar.prototype.bindYear = function () { - var cy = this.calendarYear; - cy.length = 0; - for (var i = this.beginYear; i <= this.endYear; i++) { - cy.options[cy.length] = new Option(i - + Calendar.language["year"][this.lang], i); - } -} - -// 月份下拉框绑定数据 -Calendar.prototype.bindMonth = function () { - var cm = this.calendarMonth; - cm.length = 0; - for (var i = 0; i < 12; i++) { - cm.options[cm.length] = new Option( - Calendar.language["months"][this.lang][i], i); - } -} - -// 获取小时的数据 -Calendar.prototype.getHour = function () { - return this.calendarHour.options[this.calendarHour.selectedIndex].value; -} - -// 获取分钟的数据 -Calendar.prototype.getMinute = function () { - return this.calendarMinute.options[this.calendarMinute.selectedIndex].value; -} - -// 获取秒的数据 -Calendar.prototype.getSecond = function () { - return this.calendarSecond.options[this.calendarSecond.selectedIndex].value; -} - -// 向前一月 -Calendar.prototype.goPrevMonth = function (e) { - if (this.year == this.beginYear && this.month == 0) { - return; - } - this.month--; - if (this.month == -1) { - this.year--; - this.month = 11; - } - this.date = new Date(this.year, this.month, 1, this.getHour(), this - .getMinute(), this.getSecond()); - this.changeSelect(); - this.bindData(); -} - -// 向后一月 -Calendar.prototype.goNextMonth = function (e) { - if (this.year == this.endYear && this.month == 11) { - return; - } - this.month++; - if (this.month == 12) { - this.year++; - this.month = 0; - } - this.date = new Date(this.year, this.month, 1, this.getHour(), this - .getMinute(), this.getSecond()); - this.changeSelect(); - this.bindData(); -} - -// 改变SELECT选中状态 -Calendar.prototype.changeSelect = function () { - var cy = this.calendarYear; - var cm = this.calendarMonth; - var ch = this.calendarHour; - var ci = this.calendarMinute; - var cs = this.calendarSecond; - for (var i = 0; i < cy.length; i++) { - if (cy.options[i].value == this.date.getFullYear()) { - cy[i].selected = true; - break; - } - } - for (var i = 0; i < cm.length; i++) { - if (cm.options[i].value == this.date.getMonth()) { - cm[i].selected = true; - break; - } - } - for (var i = 0; i < ch.length; i++) { - if (ch.options[i].value == this.date.getHours()) { - ch[i].selected = true; - break; - } - } - for (var i = 0; i < ci.length; i++) { - if (ci.options[i].value == this.date.getMinutes()) { - ci[i].selected = true; - break; - } - } - for (var i = 0; i < cs.length; i++) { - if (cs.options[i].value == this.date.getSeconds()) { - cs[i].selected = true; - break; - } - } -} - -// 更新年、月 -Calendar.prototype.update = function (e) { - this.year = e.calendarYear.options[e.calendarYear.selectedIndex].value; - this.month = e.calendarMonth.options[e.calendarMonth.selectedIndex].value; - this.date = new Date(this.year, this.month, 1, this.getHour(), this - .getMinute(), this.getSecond()); - this.changeSelect(); - this.bindData(); -} - -// 绑定数据到月视图 -Calendar.prototype.bindData = function () { - var calendar = this; - var dateArray = this.getMonthViewArray(this.date.getFullYear(), this.date - .getMonth()); - var tds = this.getElementById("calendarTable").getElementsByTagName("td"); - for (var i = 0; i < tds.length; i++) { - tds[i].style.backgroundColor = calendar.colors["td_bg_out"]; - tds[i].onclick = function () { - return; - } - tds[i].onmouseover = function () { - return; - } - tds[i].onmouseout = function () { - return; - } - if (i > dateArray.length - 1) { - break; - } - tds[i].innerHTML = dateArray[i]; - if (dateArray[i] != " ") { - tds[i].onclick = function () { - if (calendar.dateControl != null) { - calendar.dateControl.value = new Date(calendar.date - .getFullYear(), calendar.date.getMonth(), - this.innerHTML, calendar.getHour(), calendar - .getMinute(), calendar.getSecond()) - .format(calendar.dateFormatStyle); - } - calendar.hide(); - } - tds[i].onmouseover = function () { - this.style.backgroundColor = calendar.colors["td_bg_over"]; - } - tds[i].onmouseout = function () { - this.style.backgroundColor = calendar.colors["td_bg_out"]; - } - if (new Date().format("yyyy-MM-dd") == new Date(calendar.date - .getFullYear(), calendar.date.getMonth(), dateArray[i]) - .format("yyyy-MM-dd")) { - tds[i].style.backgroundColor = calendar.colors["cur_bg"]; - tds[i].onmouseover = function () { - this.style.backgroundColor = calendar.colors["td_bg_over"]; - } - tds[i].onmouseout = function () { - this.style.backgroundColor = calendar.colors["cur_bg"]; - } - }// end if - - // 设置已被选择的日期单元格背影色 - if (calendar.dateControl != null - && calendar.dateControl.value == new Date(calendar.date - .getFullYear(), calendar.date.getMonth(), - dateArray[i], calendar.getHour(), calendar - .getMinute(), calendar.getSecond()) - .format(calendar.dateFormatStyle)) { - tds[i].style.backgroundColor = calendar.colors["sel_bg"]; - tds[i].onmouseover = function () { - this.style.backgroundColor = calendar.colors["td_bg_over"]; - } - tds[i].onmouseout = function () { - this.style.backgroundColor = calendar.colors["sel_bg"]; - } - } - } - } -} - -// 根据年、月得到月视图数据(数组形式) -Calendar.prototype.getMonthViewArray = function (y, m) { - var mvArray = []; - var dayOfFirstDay = new Date(y, m, 1).getDay(); - var daysOfMonth = new Date(y, m + 1, 0).getDate(); - for (var i = 0; i < 42; i++) { - mvArray[i] = " "; - } - for (var i = 0; i < daysOfMonth; i++) { - mvArray[i + dayOfFirstDay] = i + 1; - } - return mvArray; -} - -// 扩展 document.getElementById(id) 多浏览器兼容性 from meizz tree source -Calendar.prototype.getElementById = function (id) { - if (typeof (id) != "string" || id == "") { - return null; - } - if (document.getElementById) { - return document.getElementById(id); - } - if (document.all) { - return document.all(id); - } - try { - return eval(id); - } catch (e) { - return null; - } -} - -// 扩展 object.getElementsByTagName(tagName) -Calendar.prototype.getElementsByTagName = function (object, tagName) { - if (document.getElementsByTagName) { - return document.getElementsByTagName(tagName); - } - if (document.all) { - return document.all.tags(tagName); - } -} - -// 取得HTML控件绝对位置 -Calendar.prototype.getAbsPoint = function (e) { - var x = e.offsetLeft; - var y = e.offsetTop; - while (e = e.offsetParent) { - x += e.offsetLeft; - y += e.offsetTop; - } - return { - "x": x, - "y": y - }; -} - -// 显示日历 -Calendar.prototype.show = function (dateObj, popControl) { - if (dateObj == null) { - throw new Error("arguments[0] is necessary") - } - this.dateControl = dateObj; - - this.date = (dateObj.value.length > 0) ? new Date(dateObj.value - .toDate(this.dateFormatStyle)) : new Date();// 若为空则显示当前月份 - this.year = this.date.getFullYear(); - this.month = this.date.getMonth(); - this.changeSelect(); - this.bindData(); - if (popControl == null) { - popControl = dateObj; - } - var xy = this.getAbsPoint(popControl); - this.panel.style.left = xy.x - 25 + "px"; - this.panel.style.top = (xy.y + dateObj.offsetHeight) + "px"; - - this.panel.style.display = ""; - this.container.style.display = ""; - - dateObj.onblur = function () { - calendar.onblur(); - } - this.container.onmouseover = function () { - isFocus = true; - } - this.container.onmouseout = function () { - isFocus = false; - } -} - -// 隐藏日历 -Calendar.prototype.hide = function () { - this.panel.style.display = "none"; - this.container.style.display = "none"; - isFocus = false; -} - -// 焦点转移时隐藏日历 -Calendar.prototype.onblur = function () { - if (!isFocus) { - this.hide(); - } -} -document -.write( - ''); - - - - diff --git a/saga-web/src/main/resources/static/js/request.js b/saga-web/src/main/resources/static/js/request.js deleted file mode 100644 index 6dcd1ab54..000000000 --- a/saga-web/src/main/resources/static/js/request.js +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -window.content = {}; -$(function () { - window.content.requests = []; - - $("#text-switch").bootstrapSwitch(); - $('#parents').multiselect(); - - $("#text-switch").on('switchChange.bootstrapSwitch', function (event, state) { - if (state == true) { - $('#view-content').hide(); - $('#text-content').show(); - } else { - $('#text-content').hide(); - $('#view-content').show(); - } - }); - - $('#send-request').click(function () { - var content = $('#content').val(); - $("#v_loading").show(); - $.ajax({ - type: "POST", - url: $("#submit-url").val(), - data: content, - contentType: "text/plain; charset=utf-8", - dataType: "json", - success: function (msg) { - $("#v_loading").hide(); - }, - error: function (req) { - alert(req.statusText); - $("#v_loading").hide(); - } - }); - }); - - $('#policyName').change(function() { - window.content.policy = $('#policyName option:selected').text(); - $('#content').val(JSON.stringify(window.content, null, 2)); - }); - - $("#addRequest").click(function() { - clearModalValues(); - var requestIds = getRequestIds(); - $("#requestModal").modal('show'); - $("#parents").multiselect("dataprovider", requestIds); - - $("#saveRequest").unbind("click").click(function(){ - window.content.policy = $('#policyName option:selected').text(); - var isUpdatedRequest = saveRequest(); - if (!isUpdatedRequest) { - var value = $('#type option:selected').text(); - var content = '' + $('#id').val() + '' + value + '' + $('#service-name').val() + - ''; - $('#requests').append(content); - $('.requests-view-button').click(function(){ - var requestId = this.id; - var request = {}; - window.content.requests.some(function(req) { - if (req.id == requestId) { - request = req; - return true; - } - return false; - }); - loadModalValues(request); - $('#requestModal').modal('show'); - }); - $('.requests-remove-button').click(function(){ - var requestId = this.id; - window.content.requests = window.content.requests.filter(function(item) { - return item.id != requestId; - }); - $('#content').val(JSON.stringify(window.content, null, 2)); - $(this).parent().parent().remove(); - }); - } - $('#requestModal').modal('hide'); - $('#content').val(JSON.stringify(window.content, null, 2)); - }); - }); - - addParameter('transaction'); - addParameter('compensation'); - - $('#reset').click(function() { - $('#content').val(''); - window.content = {}; - window.content.requests = []; - $('#policyName').prop('selectedIndex', 0); - $('#requests tbody').empty(); - }); -}); - -function clearModalValues() { - $('#id').val(''); - $('#type').prop('selectedIndex', 0); - $('#service-name').val(''); - $('#transaction-method').prop('selectedIndex', 0); - $('#transaction-path').val(''); - $('#transaction-params tr').remove(); - $('#compensation-method').prop('selectedIndex', 0); - $('#compensation-path').val(''); - $('#compensation-params tr').remove(); - $('#parents').multiselect('deselectAll', true); - $('#transaction-params-json-div').hide(); - $('#transaction-params-json').val(''); - $('#compensation-params-json-div').hide(); - $('#compensation-params-json').val(''); -} - -function loadParameterValue(operationName, operation, type) { - if (type in operation.params && operation.params[type].length != 0) { - var form = operation.params[type]; - for (var key in form) { - var content = '' + type + ''; - $('#' + operationName + '-params').append(content); - removeRowFromTable('.remove-button'); - } - } -} - -function loadParameterValues(operationName, operation) { - loadParameterValue(operationName, operation, 'form'); - loadParameterValue(operationName, operation, 'query'); - if ('json' in operation.params) { - $('#' + operationName + '-params-json').val(operation.params.json); - $('#' + operationName + '-params-json-div').show(); - } -} - -function loadOperationModalValue(operationName, operation) { - $('#' + operationName + '-method').val(operation.method); - $('#' + operationName + '-path').val(operation.path); - loadParameterValues(operationName, operation); -} - -function loadModalValues(request) { - clearModalValues(); - $('#id').val(request.id); - $('#type').val(request.type); - $('#service-name').val(request.serviceName); - - loadOperationModalValue('transaction', request.transaction); - loadOperationModalValue('compensation', request.compensation); - - var requestIds = getRequestIds(); - requestIds = requestIds.filter(function(item) { - return item.value != request.id; - }); - $("#parents").multiselect("dataprovider", requestIds); - if (request.parents != null && request.parents.length != 0) { - $('#parents').multiselect('select', request.parents); - } -} - -function retrieveParameterValues(operationName) { - var parameters = {}; - var query = {}; - var form = {}; - - if ($('#' + operationName + '-params').children().length != 0) { - $('#' + operationName + '-params tr').each(function() { - var type = $(this).find("td:nth-child(1)").html(); - var key = $(this).find("td:nth-child(2) input").val(); - var value = $(this).find("td:nth-child(3) input").val(); - if (type === 'query') { - query[key] = value; - } else { - form[key] = value; - } - }); - } - - if (!isDictEmpty(query)) { - parameters.query = query; - } - - if (!isDictEmpty(form)) { - parameters.form = form; - } - - var jsonParameter = $('#' + operationName + '-params-json').val(); - if (jsonParameter != '') { - parameters.json = jsonParameter; - } - return parameters; -} - -function retrieveOperationValues(operationName) { - var operation = {}; - operation.method = $('#' + operationName + '-method option:selected').text(); - operation.path = $('#' + operationName + '-path').val(); - operation.params = retrieveParameterValues(operationName); - return operation; -} - -function saveRequest() { - var request = {}; - request.id = $('#id').val(); - request.type = $('#type option:selected').text(); - request.serviceName = $('#service-name').val(); - - var transaction = retrieveOperationValues('transaction'); - if (!isDictEmpty(transaction)) { - request.transaction = transaction; - } - - var compensation = retrieveOperationValues('compensation'); - if (!isDictEmpty(compensation)) { - request.compensation = compensation; - } - - var parents = []; - $("#parents option:selected").each(function() { - parents.push(this.text); - }); - if (parents.length != 0) { - request.parents = parents; - } - - var isRequestUpdated = false; - window.content.requests.some(function(obj, index, arr) { - if (obj.id == request.id) { - arr[index] = request; - isRequestUpdated = true; - return true; - } - return false; - }); - if (!isRequestUpdated) { - window.content.requests.push(request); - } - return isRequestUpdated; -} - -function getRequestIds() { - var requests = window.content.requests; - var requestIds = []; - requests.forEach(function(req) { - requestIds.push({"label": req.id, "value": req.id}); - }); - return requestIds; -} - -function addParameterRowInTable(clickableSelector, tableSelector, type) { - $(clickableSelector).click(function() { - $(tableSelector).append('' + type + ''); - removeRowFromTable('.remove-button'); - }); -} - -function addJsonParameter(clickableSelector, textAreaSelector) { - $(clickableSelector).click(function() { - $(textAreaSelector).show(); - }); -} - -function addParameter(operationName) { - addParameterRowInTable('#' + operationName + '-new-query-btn', '#' + operationName + '-params', 'query'); - addParameterRowInTable('#' + operationName + '-new-form-btn', '#' + operationName + '-params', 'form'); - addJsonParameter('#' + operationName + '-new-json-btn', '#' + operationName + '-params-json-div'); -} - -function removeRowFromTable(buttonSelector) { - $(buttonSelector).click(function() { - $(this).parent().parent().remove(); - }); -} - -function isDictEmpty(obj) { - return Object.keys(obj).length === 0; -} diff --git a/saga-web/src/main/resources/static/js/table.js b/saga-web/src/main/resources/static/js/table.js deleted file mode 100644 index a0e6763ce..000000000 --- a/saga-web/src/main/resources/static/js/table.js +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -$("#content").bootstrapTable({ - method: 'get', - dataType: 'json', - url: '/saga-service/requests/', - queryParams: function queryParams(params) { - var start = $('#startPicker').find("input").val(); - var end = $('#endPicker').find("input").val(); - return { - startTime: changeDateFormat(start), - endTime: changeDateFormat(end), - pageIndex: params.pageNumber, - pageSize: params.limit - }; - - } - , - cache: false, - totalField: 'totalCount', - dataField: 'requests', - striped: true, - pageNumber: 0, - pageSize: 50, - pagination: true, - sidePagination: "server", - queryParamsType: 'limit', - columns: [ - {checkbox: true}, - { - field: 'id', - title: 'Id', - align: 'center', - width: '10%' - }, - { - field: 'sagaId', - title: 'SagaId', - align: 'center', - width: '35%' - }, - { - field: 'startTime', - title: 'StartTime', - align: 'center', - width: '20%', - //——修改——获取日期列的值进行转换 - formatter: function (value, row, index) { - return changeDateFormat(value); - } - }, - { - field: 'completedTime', - title: 'CompletedTime', - align: 'center', - width: '20%', - //——修改——获取日期列的值进行转换 - formatter: function (value, row, index) { - return changeDateFormat(value); - } - }, - { - field: 'status', - title: 'Status', - align: 'center', - width: '15%', - //查看状态详情 - formatter: function (value, row, index) { - return statusDetails(value, row); - } - } - - ] - -}); - -function refresh(params) { - - var start = $('#startPicker').find("input").val(); - var end = $('#endPicker').find("input").val(); - - var params = { - startTime: changeDateFormat(start), - endTime: changeDateFormat(end), - pageIndex: 0, - pageSize: 50 - } - $('#content').bootstrapTable('refresh', params); -} - -//时间转换 -function changeDateFormat(value) { - var date = new Date(value); - var y = date.getFullYear(); - var m = date.getMonth() + 1; - m = m < 10 ? ('0' + m) : m; - var d = date.getDate(); - d = d < 10 ? ('0' + d) : d; - var h = date.getHours(); - var minute = date.getMinutes(); - minute = minute < 10 ? ('0' + minute) : minute; - var second = date.getSeconds(); - second = second < 10 ? ('0' + second) : second; - return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second; -} - -//查看状态详情 -function statusDetails(value, row) { - var sagaId = row.sagaId; - var url = "" + value + ""; - return url; -} - diff --git a/saga-web/src/main/resources/static/request.html b/saga-web/src/main/resources/static/request.html deleted file mode 100644 index aed6f0a34..000000000 --- a/saga-web/src/main/resources/static/request.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - Request - - - - - - - - - - - - - - - -
-

Send a new Saga Request

-
-
-
-
-

Text

-
-
- -
-
- -
-
-
-
-
- -
-
- -
-
-
-
- -
-
- - -
-
-
- - - - - - - - -
IdTypeService NameViewRemove
-
- -
- - - -
- - -
-
-
-
- - - - -
-
-
-
-
- - - diff --git a/saga-web/src/main/resources/static/result.html b/saga-web/src/main/resources/static/result.html deleted file mode 100644 index aceb9790b..000000000 --- a/saga-web/src/main/resources/static/result.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - Result - - - - - - - - - - - - - - - - -
- - - - diff --git a/transports/pom.xml b/transports/pom.xml deleted file mode 100644 index d7878472a..000000000 --- a/transports/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - saga - org.apache.servicecomb.saga - 0.0.3-SNAPSHOT - - 4.0.0 - - org.apache.servicecomb.saga.transports - transports - Saga::Transports - - pom - - transport-httpclient - transport-httpclient-spring - transport-resttemplate - - - - diff --git a/transports/transport-httpclient-spring/pom.xml b/transports/transport-httpclient-spring/pom.xml deleted file mode 100644 index cec9a4b31..000000000 --- a/transports/transport-httpclient-spring/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - transports - org.apache.servicecomb.saga.transports - 0.0.3-SNAPSHOT - - 4.0.0 - - transport-httpclient-spring - Saga::Transports::HttpClient Spring - - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - - - - org.apache.servicecomb.saga - saga-core - - - org.apache.servicecomb.saga.transports - transport-httpclient - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-logging - - - - - - junit - junit - - - com.github.tomakehurst - wiremock-standalone - - - com.github.seanyinx - unit-scaffolding - - - org.springframework - spring-test - - - - diff --git a/transports/transport-httpclient-spring/src/main/java/org/apache/servicecomb/saga/transports/HttpClientTransportConfig.java b/transports/transport-httpclient-spring/src/main/java/org/apache/servicecomb/saga/transports/HttpClientTransportConfig.java deleted file mode 100644 index a10b5c623..000000000 --- a/transports/transport-httpclient-spring/src/main/java/org/apache/servicecomb/saga/transports/HttpClientTransportConfig.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.transports; - -import org.apache.servicecomb.saga.transports.httpclient.HttpClientTransport; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class HttpClientTransportConfig { - - private final int requestTimeout; - - public HttpClientTransportConfig(@Value("${saga.request.timeout:30000}") int requestTimeout) { - this.requestTimeout = requestTimeout; - } - - @Bean - @ConditionalOnMissingBean(RestTransport.class) - RestTransport transport() { - return new HttpClientTransport(requestTimeout); - } -} diff --git a/transports/transport-httpclient-spring/src/main/resources/META-INF/spring.factories b/transports/transport-httpclient-spring/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 6265ce1f9..000000000 --- a/transports/transport-httpclient-spring/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,19 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.apache.servicecomb.saga.transports.HttpClientTransportConfig diff --git a/transports/transport-httpclient-spring/src/test/java/org/apache/servicecomb/saga/transports/RestTransportTest.java b/transports/transport-httpclient-spring/src/test/java/org/apache/servicecomb/saga/transports/RestTransportTest.java deleted file mode 100644 index 2fa105d27..000000000 --- a/transports/transport-httpclient-spring/src/test/java/org/apache/servicecomb/saga/transports/RestTransportTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.transports; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static java.util.Collections.emptyMap; -import static org.apache.http.HttpStatus.SC_OK; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.net.SocketTimeoutException; - -import org.apache.servicecomb.saga.core.SagaResponse; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -import com.github.tomakehurst.wiremock.junit.WireMockRule; - -import org.apache.servicecomb.saga.core.TransportFailedException; - -@RunWith(SpringRunner.class) -@ContextConfiguration(classes = RestTransportTest.Config.class) -public class RestTransportTest { - - @Autowired - RestTransport transport; - - @ClassRule - public static final WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort()); - - private static final String normalResource = "/rest/normalResource"; - private static final String slowResource = "/rest/slowResource"; - - private String address; - - @BeforeClass - public static void init() throws Exception { - System.setProperty("saga.request.timeout", "1000"); - - stubFor(get(urlPathEqualTo(normalResource)) - .willReturn( - aResponse() - .withStatus(SC_OK))); - - stubFor(get(urlPathEqualTo(slowResource)) - .willReturn( - aResponse() - .withStatus(SC_OK) - .withFixedDelay(2000))); - } - - @AfterClass - public static void shutdown() throws Exception { - System.clearProperty("saga.request.timeout"); - } - - @Before - public void setUp() throws Exception { - address = "localhost" + ":" + wireMockRule.port(); - } - - @Test - public void ensureNormalRequestWorksFineWithRequestTimeout() throws Exception { - SagaResponse response = null; - try { - response = transport.with(address, normalResource, "GET", emptyMap()); - } catch (Exception e) { - fail("unexpected exception throw: " + e); - } - assertThat(response.succeeded(), is(true)); - } - - @Test - public void ensureSlowRequestFailsWithRequestTimeout() throws Exception { - try { - transport.with(address, slowResource, "GET", emptyMap()); - expectFailing(TransportFailedException.class); - } catch (TransportFailedException e) { - assertThat(SocketTimeoutException.class.isInstance(e.getCause()), is(true)); - } - } - - @Configuration - @ComponentScan - static class Config { - @Bean - public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { - return new PropertySourcesPlaceholderConfigurer(); - } - } -} diff --git a/transports/transport-httpclient-spring/src/test/resources/log4j2.xml b/transports/transport-httpclient-spring/src/test/resources/log4j2.xml deleted file mode 100644 index 58924c686..000000000 --- a/transports/transport-httpclient-spring/src/test/resources/log4j2.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/transports/transport-httpclient/pom.xml b/transports/transport-httpclient/pom.xml deleted file mode 100644 index 8cfd5b427..000000000 --- a/transports/transport-httpclient/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - transports - org.apache.servicecomb.saga.transports - 0.0.3-SNAPSHOT - - 4.0.0 - - transport-httpclient - Saga::Transports::HttpClient - - - - org.apache.servicecomb.saga - saga-core - - - org.apache.httpcomponents - fluent-hc - 4.5.3 - - - io.kamon - kamon-core_2.12 - - - io.kamon - kamon-annotation_2.12 - - - - junit - junit - - - com.github.tomakehurst - wiremock-standalone - - - com.github.seanyinx - unit-scaffolding - - - - diff --git a/transports/transport-httpclient/src/main/java/org/apache/servicecomb/saga/transports/httpclient/HttpClientTransport.java b/transports/transport-httpclient/src/main/java/org/apache/servicecomb/saga/transports/httpclient/HttpClientTransport.java deleted file mode 100644 index 0a9e16045..000000000 --- a/transports/transport-httpclient/src/main/java/org/apache/servicecomb/saga/transports/httpclient/HttpClientTransport.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.transports.httpclient; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.function.Function; - -import org.apache.http.HttpResponse; -import org.apache.http.client.fluent.Form; -import org.apache.http.client.fluent.Request; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.entity.ContentType; -import org.apache.logging.log4j.core.util.IOUtils; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.SuccessfulSagaResponse; - -import org.apache.servicecomb.saga.core.TransportFailedException; -import org.apache.servicecomb.saga.transports.RestTransport; -import kamon.annotation.EnableKamon; -import kamon.annotation.Segment; - -@EnableKamon -public class HttpClientTransport implements RestTransport { - - private final int requestTimeout; - private static final int DEFAULT_REQUEST_TIMEOUT = 30000; - - private static final Map> requestFactories = new HashMap>() {{ - put("GET", Request::Get); - put("POST", Request::Post); - put("PUT", Request::Put); - put("DELETE", Request::Delete); - }}; - - public HttpClientTransport() { - this(DEFAULT_REQUEST_TIMEOUT); - } - - public HttpClientTransport(int requestTimeout) { - this.requestTimeout = requestTimeout; - } - - @Segment(name = "transport", category = "network", library = "kamon") - @Override - public SagaResponse with(String address, String path, String method, Map> params) { - URIBuilder builder = new URIBuilder().setScheme("http").setHost(address).setPath(path); - - if (params.containsKey("query")) { - for (Entry entry : params.get("query").entrySet()) { - builder.addParameter(entry.getKey(), entry.getValue()); - } - } - - try { - URI uri = builder.build(); - Request request = requestFactories.getOrDefault( - method.toUpperCase(), - exceptionThrowingFunction(method)).apply(uri); - - request.socketTimeout(requestTimeout); - if (params.containsKey("json")) { - request.bodyString(params.get("json").get("body"), ContentType.APPLICATION_JSON); - } - - if (params.containsKey("form")) { - Form form = Form.form(); - for (Entry entry : params.get("form").entrySet()) { - form.add(entry.getKey(), entry.getValue()).build(); - } - request.bodyForm(form.build()); - } - - return this.on(request); - } catch (URISyntaxException e) { - throw new TransportFailedException("Wrong request URI", e); - } - } - - private Function exceptionThrowingFunction(String method) { - return u -> { - throw new TransportFailedException("No such method " + method); - }; - } - - private SagaResponse on(Request request) { - try { - HttpResponse httpResponse = request.execute().returnResponse(); - int statusCode = httpResponse.getStatusLine().getStatusCode(); - String content = IOUtils.toString(new InputStreamReader(httpResponse.getEntity().getContent())); - if (statusCode >= 200 && statusCode < 300) { - return new SuccessfulSagaResponse(content); - } - throw new TransportFailedException("The remote service returned with status code " + statusCode - + ", reason " + httpResponse.getStatusLine().getReasonPhrase() - + ", and content " + content); - } catch (IOException e) { - throw new TransportFailedException("Network Error", e); - } - } -} diff --git a/transports/transport-httpclient/src/test/java/org/apache/servicecomb/saga/transports/httpclient/HttpClientTransportTest.java b/transports/transport-httpclient/src/test/java/org/apache/servicecomb/saga/transports/httpclient/HttpClientTransportTest.java deleted file mode 100644 index 1c32d3eb0..000000000 --- a/transports/transport-httpclient/src/test/java/org/apache/servicecomb/saga/transports/httpclient/HttpClientTransportTest.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.transports.httpclient; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.containing; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_OK; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import java.net.SocketTimeoutException; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; - -import com.github.tomakehurst.wiremock.junit.WireMockRule; - -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.TransportFailedException; -import org.apache.servicecomb.saga.transports.RestTransport; - -public class HttpClientTransportTest { - - @ClassRule - public static final WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort()); - - private static final String usableResource = "/rest/usableResource"; - private static final String faultyResource = "/rest/faultyResource"; - private static final String slowResource = "/rest/slowResource"; - private static final String usableResponse = "hello world"; - private static final String faultyResponse = "no such resource"; - private static final String json = "{\"hello\", \"world\"}"; - - private String address; - - private final RestTransport transport = new HttpClientTransport(); - - @BeforeClass - public static void setUpClass() throws Exception { - stubFor(get(urlPathEqualTo(usableResource)) - .withQueryParam("foo", equalTo("bar")) - .withQueryParam("hello", equalTo("world")) - .willReturn( - aResponse() - .withStatus(SC_OK) - .withBody(usableResponse))); - - stubFor(post(urlPathEqualTo(faultyResource)) - .withQueryParam("foo", equalTo("bar")) - .withRequestBody(containing("hello=world&jesus=christ")) - .willReturn( - aResponse() - .withStatus(SC_INTERNAL_SERVER_ERROR) - .withBody(faultyResponse))); - - stubFor(put(urlPathEqualTo(usableResource)) - .withQueryParam("foo", equalTo("bar")) - .withRequestBody(equalTo(json)) - .willReturn( - aResponse() - .withStatus(SC_OK) - .withBody(usableResponse))); - - stubFor(get(urlPathEqualTo(slowResource)) - .willReturn( - aResponse() - .withStatus(SC_OK) - .withFixedDelay(2000))); - } - - @Before - public void setUp() throws Exception { - address = "localhost" + ":" + wireMockRule.port(); - } - - @Test - public void getsRequestFromRemote() { - Map> requests = singletonMap("query", map("foo", "bar", "hello", "world")); - - SagaResponse response = transport.with(address, usableResource, "GET", requests); - - assertThat(response.succeeded(), is(true)); - assertThat(response.body(), containsString(usableResponse)); - } - - @Test - public void putsRequestToRemote() { - Map> requests = new HashMap<>(); - requests.put("query", singletonMap("foo", "bar")); - requests.put("json", singletonMap("body", json)); - - SagaResponse response = transport.with(address, usableResource, "PUT", requests); - - assertThat(response.succeeded(), is(true)); - assertThat(response.body(), containsString(usableResponse)); - } - - @Test - public void blowsUpWhenRemoteResponseIsNot2XX() { - Map> requests = new HashMap<>(); - requests.put("query", singletonMap("foo", "bar")); - requests.put("form", map("hello", "world", "jesus", "christ")); - - try { - transport.with(address, faultyResource, "POST", requests); - expectFailing(TransportFailedException.class); - } catch (TransportFailedException e) { - assertThat(e.getMessage(), containsString("The remote service returned with status code 500")); - } - } - - @Test - public void blowsUpWhenRemoteIsNotReachable() { - try { - transport.with("http://somewhere:9090", faultyResource, "DELETE", emptyMap()); - expectFailing(TransportFailedException.class); - } catch (TransportFailedException e) { - assertThat(e.getMessage(), is("Network Error")); - } - } - - @Test - public void blowsUpWhenMethodIsUnknown() { - try { - transport.with(address, usableResource, "Blah", emptyMap()); - expectFailing(TransportFailedException.class); - } catch (TransportFailedException e) { - assertThat(e.getMessage(), is("No such method Blah")); - } - } - - @Test - public void blowsUpWhenUriIsMalformed() { - try { - transport.with("\\", usableResource, "GET", emptyMap()); - expectFailing(TransportFailedException.class); - } catch (TransportFailedException e) { - assertThat(e.getMessage(), is("Wrong request URI")); - } - } - - @Test - public void blowsUpWhenRequestTimeout() { - HttpClientTransport transportWithShortTimeout = new HttpClientTransport(1000); - try { - transportWithShortTimeout.with(address, slowResource, "GET", emptyMap()); - expectFailing(TransportFailedException.class); - } catch (TransportFailedException e) { - assertThat(SocketTimeoutException.class.isInstance(e.getCause()), is(true)); - } - } - - private Map map(String... pairs) { - return new LinkedHashMap(){{ - for (int i = 0; i < pairs.length; i+=2) { - put(pairs[i], pairs[i + 1]); - } - }}; - } -} diff --git a/transports/transport-httpclient/src/test/resources/log4j2.xml b/transports/transport-httpclient/src/test/resources/log4j2.xml deleted file mode 100644 index 58924c686..000000000 --- a/transports/transport-httpclient/src/test/resources/log4j2.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/transports/transport-resttemplate/pom.xml b/transports/transport-resttemplate/pom.xml deleted file mode 100644 index 8e63146a7..000000000 --- a/transports/transport-resttemplate/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - transports - org.apache.servicecomb.saga.transports - 0.0.3-SNAPSHOT - - 4.0.0 - - transport-resttemplate - Saga::Transports::RestTemplate - - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - - - - org.apache.servicecomb.saga - saga-core - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-logging - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-logging - - - - - - diff --git a/transports/transport-resttemplate/src/main/java/org/apache/servicecomb/saga/transports/resttemplate/RestTemplateTransport.java b/transports/transport-resttemplate/src/main/java/org/apache/servicecomb/saga/transports/resttemplate/RestTemplateTransport.java deleted file mode 100644 index 86f7ec798..000000000 --- a/transports/transport-resttemplate/src/main/java/org/apache/servicecomb/saga/transports/resttemplate/RestTemplateTransport.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.saga.transports.resttemplate; - -import static java.util.Collections.emptyMap; -import static org.springframework.http.HttpMethod.DELETE; -import static org.springframework.http.HttpMethod.GET; -import static org.springframework.http.HttpMethod.POST; -import static org.springframework.http.HttpMethod.PUT; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED; -import static org.springframework.http.MediaType.APPLICATION_JSON; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiFunction; - -import org.apache.servicecomb.saga.core.SagaRequest; -import org.apache.servicecomb.saga.core.SagaResponse; -import org.apache.servicecomb.saga.core.SuccessfulSagaResponse; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.web.client.ResponseErrorHandler; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; - -import org.apache.servicecomb.saga.core.TransportFailedException; -import org.apache.servicecomb.saga.transports.RestTransport; - -public class RestTemplateTransport implements RestTransport { - - private final String protocol; - private final RestTemplate restTemplate; - private final Map>, ResponseEntity>> methodMapping = new HashMap<>(); - - public RestTemplateTransport(RestTemplate restTemplate, String protocol) { - this.protocol = protocol; - this.restTemplate = restTemplate; - this.restTemplate.setErrorHandler(new ResponseErrorHandler() { - @Override - public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException { - return false; - } - - @Override - public void handleError(ClientHttpResponse clientHttpResponse) throws IOException { - } - }); - - methodMapping.put(GET.name(), exchange(GET)); - methodMapping.put(PUT.name(), exchange(PUT)); - methodMapping.put(POST.name(), exchange(POST)); - methodMapping.put(DELETE.name(), exchange(DELETE)); - } - - @Override - public SagaResponse with(String address, String path, String method, Map> params) { - String url = buildUrl(address, path, params); - - try { - ResponseEntity responseEntity = methodHandler(method).apply(url, params); - return new SuccessfulSagaResponse(responseEntity.getBody()); - } catch (Throwable e) { - throw new TransportFailedException( - String.format("The remote service %s failed to serve the %s request to %s ", address, method, path), - e); - } - } - - private String buildUrl(String address, String path, Map> params) { - UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromPath(path); - params.getOrDefault(SagaRequest.PARAM_QUERY, emptyMap()) - .forEach(uriComponentsBuilder::queryParam); - - return protocol + address + uriComponentsBuilder.build().toString(); - } - - private BiFunction>, ResponseEntity> methodHandler(String method) { - return methodMapping.getOrDefault(method.toUpperCase(), (url, params) -> { - throw new TransportFailedException("No such method " + method); - }); - } - - private BiFunction>, ResponseEntity> exchange(HttpMethod method) { - return (url, params) -> restTemplate.exchange(url, method, request(params), String.class); - } - - private HttpEntity request(Map> params) { - HttpHeaders headers = new HttpHeaders(); - - if (params.containsKey(SagaRequest.PARAM_JSON)) { - headers.setContentType(APPLICATION_JSON); - return new HttpEntity<>(params.get(SagaRequest.PARAM_JSON).get(SagaRequest.PARAM_JSON_BODY), headers); - } - - if (params.containsKey(SagaRequest.PARAM_FORM)) { - headers.setContentType(APPLICATION_FORM_URLENCODED); - return new HttpEntity<>(params.get(SagaRequest.PARAM_FORM), headers); - } - - return null; - } -} From fbb0dd57a8b70ba736e532771393ba565e5aef29 Mon Sep 17 00:00:00 2001 From: Yang Bo Date: Fri, 2 Mar 2018 11:45:16 +0800 Subject: [PATCH 2/2] SCB-363 Rename pack-demo to booking --- README.md | 4 ++-- README_ZH.md | 4 ++-- saga-demo/{pack-demo => booking}/README.md | 0 saga-demo/{pack-demo => booking}/booking/pom.xml | 2 +- .../servicecomb/saga/demo/pack/booking/Application.java | 0 .../servicecomb/saga/demo/pack/booking/BookingController.java | 0 .../booking/src/main/resources/application.yaml | 0 saga-demo/{pack-demo => booking}/car/pom.xml | 2 +- .../apache/servicecomb/saga/demo/pack/car/Application.java | 0 .../org/apache/servicecomb/saga/demo/pack/car/CarBooking.java | 0 .../servicecomb/saga/demo/pack/car/CarBookingController.java | 0 .../servicecomb/saga/demo/pack/car/CarBookingService.java | 0 .../car/src/main/resources/application.yaml | 0 saga-demo/{pack-demo => booking}/docker-compose.mysql.yaml | 0 saga-demo/{pack-demo => booking}/docker-compose.yaml | 0 saga-demo/{pack-demo => booking}/hotel/pom.xml | 2 +- .../apache/servicecomb/saga/demo/pack/hotel/Application.java | 0 .../apache/servicecomb/saga/demo/pack/hotel/HotelBooking.java | 0 .../saga/demo/pack/hotel/HotelBookingController.java | 0 .../servicecomb/saga/demo/pack/hotel/HotelBookingService.java | 0 .../hotel/src/main/resources/application.yaml | 0 saga-demo/{pack-demo => booking}/pom.xml | 4 ++-- saga-demo/pom.xml | 2 +- 23 files changed, 10 insertions(+), 10 deletions(-) rename saga-demo/{pack-demo => booking}/README.md (100%) rename saga-demo/{pack-demo => booking}/booking/pom.xml (98%) rename saga-demo/{pack-demo => booking}/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/Application.java (100%) rename saga-demo/{pack-demo => booking}/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/BookingController.java (100%) rename saga-demo/{pack-demo => booking}/booking/src/main/resources/application.yaml (100%) rename saga-demo/{pack-demo => booking}/car/pom.xml (98%) rename saga-demo/{pack-demo => booking}/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/Application.java (100%) rename saga-demo/{pack-demo => booking}/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBooking.java (100%) rename saga-demo/{pack-demo => booking}/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingController.java (100%) rename saga-demo/{pack-demo => booking}/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingService.java (100%) rename saga-demo/{pack-demo => booking}/car/src/main/resources/application.yaml (100%) rename saga-demo/{pack-demo => booking}/docker-compose.mysql.yaml (100%) rename saga-demo/{pack-demo => booking}/docker-compose.yaml (100%) rename saga-demo/{pack-demo => booking}/hotel/pom.xml (98%) rename saga-demo/{pack-demo => booking}/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/Application.java (100%) rename saga-demo/{pack-demo => booking}/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBooking.java (100%) rename saga-demo/{pack-demo => booking}/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingController.java (100%) rename saga-demo/{pack-demo => booking}/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingService.java (100%) rename saga-demo/{pack-demo => booking}/hotel/src/main/resources/application.yaml (100%) rename saga-demo/{pack-demo => booking}/pom.xml (95%) diff --git a/README.md b/README.md index 61c9c8f8c..419033938 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,10 @@ Saga is composed of **alpha** and **omega**. The following diagram shows the relationships among alpha, omega and services. ![Saga Pack Architecture](docs/static_files/pack.png) -See [Saga Pack Design](docs/design.md) for details. If you are interested in our previous architecture, please move forward to [Old Saga's Documentation](docs/old_saga.md). +See [Saga Pack Design](docs/design.md) for details. ## Get Started -See [Booking Demo](saga-demo/pack-demo/README.md) for details. +See [Booking Demo](saga-demo/booking/README.md) for details. ## User Guide See [User Guide](docs/user_guide.md) for details. diff --git a/README_ZH.md b/README_ZH.md index ac5f8a3ee..1b055926a 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -17,10 +17,10 @@ Saga是由 **alpha** 和 **omega**组成,其中: 下图展示了alpha, omega以及微服务三者的关系: ![Saga Pack 架构](docs/static_files/pack.png) -详情可浏览[Saga Pack 设计文档](docs/design_zh.md). 如果您对Saga的上一代架构感兴趣,可移步至[上一代Saga文档](docs/old_saga.md)了解详情。 +详情可浏览[Saga Pack 设计文档](docs/design_zh.md). ## 快速入门 -详情可浏览[出行预订示例](saga-demo/pack-demo/README.md)。 +详情可浏览[出行预订示例](saga-demo/booking/README.md)。 ## 用户指南 详情可浏览[用户指南](docs/user_guide_zh.md)。 diff --git a/saga-demo/pack-demo/README.md b/saga-demo/booking/README.md similarity index 100% rename from saga-demo/pack-demo/README.md rename to saga-demo/booking/README.md diff --git a/saga-demo/pack-demo/booking/pom.xml b/saga-demo/booking/booking/pom.xml similarity index 98% rename from saga-demo/pack-demo/booking/pom.xml rename to saga-demo/booking/booking/pom.xml index 1f88668ca..8d75deb42 100644 --- a/saga-demo/pack-demo/booking/pom.xml +++ b/saga-demo/booking/booking/pom.xml @@ -18,7 +18,7 @@ - pack-demo + booking org.apache.servicecomb.saga.demo 0.0.3-SNAPSHOT diff --git a/saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/Application.java b/saga-demo/booking/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/Application.java similarity index 100% rename from saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/Application.java rename to saga-demo/booking/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/Application.java diff --git a/saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/BookingController.java b/saga-demo/booking/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/BookingController.java similarity index 100% rename from saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/BookingController.java rename to saga-demo/booking/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/BookingController.java diff --git a/saga-demo/pack-demo/booking/src/main/resources/application.yaml b/saga-demo/booking/booking/src/main/resources/application.yaml similarity index 100% rename from saga-demo/pack-demo/booking/src/main/resources/application.yaml rename to saga-demo/booking/booking/src/main/resources/application.yaml diff --git a/saga-demo/pack-demo/car/pom.xml b/saga-demo/booking/car/pom.xml similarity index 98% rename from saga-demo/pack-demo/car/pom.xml rename to saga-demo/booking/car/pom.xml index 78ebd5feb..667dc8de0 100644 --- a/saga-demo/pack-demo/car/pom.xml +++ b/saga-demo/booking/car/pom.xml @@ -18,7 +18,7 @@ - pack-demo + booking org.apache.servicecomb.saga.demo 0.0.3-SNAPSHOT diff --git a/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/Application.java b/saga-demo/booking/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/Application.java similarity index 100% rename from saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/Application.java rename to saga-demo/booking/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/Application.java diff --git a/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBooking.java b/saga-demo/booking/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBooking.java similarity index 100% rename from saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBooking.java rename to saga-demo/booking/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBooking.java diff --git a/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingController.java b/saga-demo/booking/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingController.java similarity index 100% rename from saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingController.java rename to saga-demo/booking/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingController.java diff --git a/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingService.java b/saga-demo/booking/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingService.java similarity index 100% rename from saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingService.java rename to saga-demo/booking/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingService.java diff --git a/saga-demo/pack-demo/car/src/main/resources/application.yaml b/saga-demo/booking/car/src/main/resources/application.yaml similarity index 100% rename from saga-demo/pack-demo/car/src/main/resources/application.yaml rename to saga-demo/booking/car/src/main/resources/application.yaml diff --git a/saga-demo/pack-demo/docker-compose.mysql.yaml b/saga-demo/booking/docker-compose.mysql.yaml similarity index 100% rename from saga-demo/pack-demo/docker-compose.mysql.yaml rename to saga-demo/booking/docker-compose.mysql.yaml diff --git a/saga-demo/pack-demo/docker-compose.yaml b/saga-demo/booking/docker-compose.yaml similarity index 100% rename from saga-demo/pack-demo/docker-compose.yaml rename to saga-demo/booking/docker-compose.yaml diff --git a/saga-demo/pack-demo/hotel/pom.xml b/saga-demo/booking/hotel/pom.xml similarity index 98% rename from saga-demo/pack-demo/hotel/pom.xml rename to saga-demo/booking/hotel/pom.xml index 8b4dc09ce..234d4db60 100644 --- a/saga-demo/pack-demo/hotel/pom.xml +++ b/saga-demo/booking/hotel/pom.xml @@ -18,7 +18,7 @@ - pack-demo + booking org.apache.servicecomb.saga.demo 0.0.3-SNAPSHOT diff --git a/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/Application.java b/saga-demo/booking/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/Application.java similarity index 100% rename from saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/Application.java rename to saga-demo/booking/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/Application.java diff --git a/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBooking.java b/saga-demo/booking/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBooking.java similarity index 100% rename from saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBooking.java rename to saga-demo/booking/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBooking.java diff --git a/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingController.java b/saga-demo/booking/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingController.java similarity index 100% rename from saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingController.java rename to saga-demo/booking/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingController.java diff --git a/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingService.java b/saga-demo/booking/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingService.java similarity index 100% rename from saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingService.java rename to saga-demo/booking/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingService.java diff --git a/saga-demo/pack-demo/hotel/src/main/resources/application.yaml b/saga-demo/booking/hotel/src/main/resources/application.yaml similarity index 100% rename from saga-demo/pack-demo/hotel/src/main/resources/application.yaml rename to saga-demo/booking/hotel/src/main/resources/application.yaml diff --git a/saga-demo/pack-demo/pom.xml b/saga-demo/booking/pom.xml similarity index 95% rename from saga-demo/pack-demo/pom.xml rename to saga-demo/booking/pom.xml index 8deb910a7..3c39d9dda 100644 --- a/saga-demo/pack-demo/pom.xml +++ b/saga-demo/booking/pom.xml @@ -24,8 +24,8 @@ 4.0.0 - pack-demo - Saga::Demo::Pack + booking + Saga::Demo::Booking pom diff --git a/saga-demo/pom.xml b/saga-demo/pom.xml index 43f417f44..69bb12431 100644 --- a/saga-demo/pom.xml +++ b/saga-demo/pom.xml @@ -30,7 +30,7 @@ pom - pack-demo + booking