All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.ks.eventstore2.saga.Saga Maven / Gradle / Ivy

package no.ks.eventstore2.saga;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import no.ks.eventstore2.Event;
import no.ks.eventstore2.reflection.HandlerFinder;

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

import akka.actor.ActorRef;
import akka.actor.UntypedActor;

public abstract class Saga extends UntypedActor {

	private Logger log = LoggerFactory.getLogger(this.getClass());

	public static final byte STATE_INITIAL = 0;
	public static final byte STATE_FINISHED = Byte.MAX_VALUE;

	protected String id;

	private byte state = STATE_INITIAL;
	protected ActorRef commandDispatcher;
    protected SagaRepository repository;
	private Map, Method> handleEventMap;

	public Saga(String id, ActorRef commandDispatcher, SagaRepository repository) {
		this.id = id;
        this.commandDispatcher = commandDispatcher;
        this.repository = repository;
	}

    @Override
    public void preStart() throws Exception {
        super.preStart();
        loadPersistedState();
		init();
    }

	@Override
	public void onReceive(Object o) {
		try{
            if(o instanceof Event){
                log.debug("Received event {}", o);
                Method method = HandlerFinder.findHandlingMethod(handleEventMap, (Event) o);
                method.invoke(this,o);
            }
        } catch(Exception e){
            log.error("Saga threw exception when handling message: ", e);
            throw new RuntimeException("Saga threw exception when handling message: ", e);
        }
	}

	private void loadPersistedState() {
        state = repository.getState(this.getClass(),id);
    }

    public String getId() {
		return id;
	}

	public byte getState() {
		return state;
	}

	protected void transitionState(byte state){
        if(getState() == state) {
        	return;
        }
		this.state = state;
		try {
	        repository.saveState(this.getClass(), id, state);
		} catch(Exception e){
			log.error("Failed to save state for class " + this.getClass() + " id "  + id + " state " + state);
			throw new RuntimeException(e);
		}
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		Saga saga = (Saga) o;

		if (id != null ? !id.equals(saga.id) : saga.id != null) return false;

		return true;
	}

	@Override
	public int hashCode() {
		return id != null ? id.hashCode() : 0;
	}

	public void forceSetState(byte state) {
		this.state = state;
	}

	private void init() {
		handleEventMap = new HashMap, Method>();
		try {
			Class projectionClass = this.getClass();
			ListensTo annotation = projectionClass.getAnnotation(ListensTo.class);
			if (annotation != null) {
				EventIdBind[] handledEventClasses = annotation.value();
				for (EventIdBind eventIdBind : handledEventClasses) {
					Method handleEventMethod = null;
					handleEventMethod = projectionClass.getMethod("handleEvent", eventIdBind.eventClass());
					handleEventMap.put(eventIdBind.eventClass(), handleEventMethod);
				}


			}

            handleEventMap.putAll(HandlerFinder.getEventHandlers(this.getClass()));

		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy