Skip to content
Prev Previous commit
Next Next commit
add choreogr
  • Loading branch information
Besok committed Nov 9, 2019
commit 09b4663b9a15c406b899bc6900320a8361c92253
27 changes: 17 additions & 10 deletions saga/src/main/java/com/iluwatar/saga/choreography/Chapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,20 @@
*/
package com.iluwatar.saga.choreography;

import com.iluwatar.saga.orchestration.ChapterResult;

/**
* Chapter is an interface representing a contract for an external service.
* @param <K> is type for passing params
*/
public interface Chapter<K> {
* In that case, a service needs to make a decision what to do further
* hence the server needs to get all context representing {@link Saga}
* */
public interface Chapter {

/**
* In that case, every method is responsible to make a decision on what to do then
* @param saga incoming saga
* @return saga result
*/
Saga execute(Saga saga);

/**
* @return service name.
Expand All @@ -37,17 +44,17 @@ public interface Chapter<K> {

/**
* The operation executed in general case.
* @param value incoming value
* @return result {@link ChapterResult}
* @param saga incoming saga
* @return result {@link Saga}
*/
ChapterResult<K> process(K value);
Saga process(Saga saga);

/**
* The operation executed in rollback case.
* @param value incoming value
* @return result {@link ChapterResult}
* @param saga incoming saga
* @return result {@link Saga}
*/
ChapterResult<K> rollback(K value);
Saga rollback(Saga saga);


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.saga.choreography;


/**
* Class representing a service to book a fly
*/
public class FlyBookingService extends Service {
public FlyBookingService(ServiceDiscoveryService service) {
super(service);
}

@Override
public String getName() {
return "booking a Fly";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.saga.choreography;


/**
* Class representing a service to book a hotel
*/
public class HotelBookingService extends Service {
public HotelBookingService(ServiceDiscoveryService service) {
super(service);
}

@Override
public String getName() {
return "booking a Hotel";
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.saga.choreography;


/**
* Class representing a service to init a new order.
*/
public class OrderService extends Service{

public OrderService(ServiceDiscoveryService service) {
super(service);
}

@Override
public String getName() {
return "init an order";
}
}
125 changes: 125 additions & 0 deletions saga/src/main/java/com/iluwatar/saga/choreography/Saga.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,138 @@
*/
package com.iluwatar.saga.choreography;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* Saga representation.
* Saga consists of chapters.
* Every Chapter is executed a certain service.
*/
public class Saga {

private List<Chapter> chapters;
private int pos;
private boolean forward;
private boolean finished;


public static Saga create() {
return new Saga();
}
public SagaResult getResult() {
return !finished ?
SagaResult.PROGRESS :
forward ?
SagaResult.FINISHED :
SagaResult.ROLLBACKED;
}
public Saga chapter(String name) {
this.chapters.add(new Chapter(name));
return this;
}
public Saga setInValue(Object value){
if(chapters.isEmpty()){
return this;
}
chapters.get(chapters.size()-1).setInValue(value);
return this;
}
public Object getCurrentValue(){
return chapters.get(pos).getInValue();
}
public void setCurrentValue(Object value){
chapters.get(pos).setInValue(value);
}
public void setCurrentStatus(ChapterResult result){
chapters.get(pos).setResult(result);
}

void setFinished(boolean finished) {
this.finished = finished;
}
boolean isForward() {
return forward;
}
int forward() {
return ++pos;
}

int back() {
this.forward = false;
return --pos;
}


public Saga() {
this.chapters = new ArrayList<>();
this.pos = 0;
this.forward = true;
this.finished = false;
}

Chapter getCurrent() {
return chapters.get(pos);
}


boolean isPresent() {
return pos >= 0 && pos < chapters.size();
}
boolean isCurrentSuccess(){
return chapters.get(pos).isSuccess();
}

/***
* Class presents a chapter status and incoming parameters(incoming parameter transforms to outcoming parameter)
*/
public static class Chapter {
private String name;
private ChapterResult result;
private Object inValue;


public Chapter(String name) {
this.name = name;
this.result = ChapterResult.INIT;
}

public Object getInValue() {
return inValue;
}

public void setInValue(Object object) {
this.inValue = object;
}

public String getName() {
return name;
}
public void setResult(ChapterResult result){
this.result = result;
}

public boolean isSuccess(){
return result == ChapterResult.SUCCESS;
}
}


public enum ChapterResult {
INIT, SUCCESS, ROLLBACK
}

public enum SagaResult {
PROGRESS, FINISHED, ROLLBACKED
}

@Override
public String toString() {
return "Saga{" +
"chapters=" + Arrays.toString(chapters.toArray()) +
", pos=" + pos +
", forward=" + forward +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* The MIT License
* Copyright © 2014-2019 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.saga.choreography;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This pattern is used in distributed services to perform a group of operations atomically.
* This is an analog of transaction in a database but in terms of microservices architecture this is executed
* in a distributed environment
* <p>
* A saga is a sequence of local transactions in a certain context. If one transaction fails for some reason,
* the saga executes compensating transactions(rollbacks) to undo the impact of the preceding transactions.
* <p>
* In this approach, there are no mediators or orchestrators services.
* All chapters are handled and moved by services manually.
* <p>
* The major difference with choreography saga is an ability to handle crashed services
* (otherwise in choreography services very hard to prevent a saga if one of them has been crashed)
*
* @see com.iluwatar.saga.choreography.Saga
* @see Service
*/
public class SagaApplication {
private static final Logger logger = LoggerFactory.getLogger(SagaApplication.class);

public static void main(String[] args) {
ServiceDiscoveryService sd = serviceDiscovery();
Chapter service = sd.findAny();
Saga goodOrderSaga = service.execute(newSaga("good_order"));
Saga badOrderSaga = service.execute(newSaga("bad_order"));
logger.info("orders: goodOrder is {}, badOrder is {}",
goodOrderSaga.getResult(), badOrderSaga.getResult());

}


private static Saga newSaga(Object value) {
return Saga
.create()
.chapter("init an order").setInValue(value)
.chapter("booking a Fly")
.chapter("booking a Hotel")
.chapter("withdrawing Money");
}

private static ServiceDiscoveryService serviceDiscovery() {
ServiceDiscoveryService sd = new ServiceDiscoveryService();
return sd
.discover(new OrderService(sd))
.discover(new FlyBookingService(sd))
.discover(new HotelBookingService(sd))
.discover(new WithdrawMoneyService(sd));
}
}
Loading