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

cn.org.atool.fluentmachine.persistence.ContextTestSaver Maven / Gradle / Ivy

There is a newer version: 0.3.3
Show newest version
package cn.org.atool.fluentmachine.persistence;

import cn.org.atool.fluentmachine.context.Context;
import cn.org.atool.fluentmachine.context.FireContext;
import cn.org.atool.fluentmachine.exception.LockException;
import cn.org.atool.fluentmachine.saver.ContextSaver;
import cn.org.atool.fluentmachine.state.IName;
import lombok.Getter;
import lombok.Setter;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 上下文保存测试
 *
 * @author darui.wu
 */
public class ContextTestSaver implements ContextSaver {
    @Getter
    @Setter
    private long lockDuration = 100L;

    private volatile Context context = null;
    /**
     * 状态机运行路径
     */
    @Getter
    private final List paths = new ArrayList<>();

    @Override
    public boolean isExistContext(String machineId, String tradeNo) {
        return context != null;
    }

    private String lockBy = null;

    public void cleanup() {
        context = null;
    }

    @Override
    public void saveContext(Context ctx, FireContext fire, boolean isNew) {
        synchronized (getLock(ctx.getMachineId(), ctx.getTradeNo())) {
            this.context = ContextHelper.copy(ctx);
            this.paths.add(fire.toString());
        }
    }

    @Override
    public boolean lock(Context ctx, String lockVersion, Object event) {
        synchronized (getLock(ctx.getMachineId(), ctx.getTradeNo())) {
            if (this.context == null) {
                return true;
            }
            if (this.canLock(ctx)) {
                this.context.setLockVersion(lockVersion);
                this.context.setLockExpireSecond(new Date().getTime() + this.getLockDuration());
                this.lockBy = IName.name(event) + ":" + ctx.getStates();
                return true;
            } else {
                throw new LockException("The context[machineId=%s, tradeNo=%s] is locked and not expired, lock by:%s",
                    ctx.getMachineId(), ctx.getTradeNo(), this.lockBy);
            }
        }
    }

    @Override
    public boolean unlock(Context ctx) {
        synchronized (getLock(ctx.getMachineId(), ctx.getTradeNo())) {
            if (this.context == null) {
                return true;
            }
            if (canLock(ctx)) {
                this.context.setLockVersion(null);
                this.context.setLockExpireSecond(0L);
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * 未上锁或锁相同
     *
     * @param context
     * @return
     */
    private boolean canLock(Context context) {
        String oldLock = this.context.getLockVersion();
        return this.expiredLock() || Objects.equals(oldLock, context.getLockVersion());
    }

    /**
     * 锁过期
     *
     * @return
     */
    private boolean expiredLock() {
        String oldLock = this.context.getLockVersion();
        if (oldLock == null || oldLock.trim().isEmpty() || Objects.equals(oldLock, "0")) {
            return true;
        } else {
            return this.context.getLockExpireSecond() <= new Date().getTime();
        }
    }

    @Override
    public  Context loadContext(String machineId, String tradeNo, boolean ignoreLock, Class klass) {
        synchronized (getLock(machineId, tradeNo)) {
            if (ignoreLock) {
                return ContextHelper.copy(context);
            } else if (this.expiredLock()) {
                return ContextHelper.copy(context);
            } else {
                throw new LockException("The lock of context[machineId=%s, tradeNo=%s] not expired.", machineId, tradeNo);
            }
        }
    }

    /**
     * 返回路径描述
     *
     * @param delimiter 分隔符
     * @return
     */
    public String getPaths(String delimiter) {
        return this.getPaths().stream().collect(Collectors.joining(delimiter));
    }

    private static Map locks = new HashMap<>();

    private synchronized String getLock(String machineId, String tradeNo) {
        String lock = machineId + tradeNo;
        if (!locks.containsKey(lock)) {
            locks.put(lock, lock);
        }
        return locks.get(lock);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy