Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
WalletImpl.java 7.28 KiB
package fucoin.wallet;

import akka.actor.ActorRef;
import akka.actor.Props;
import fucoin.actions.ClientAction;
import fucoin.actions.join.ActionJoin;
import fucoin.actions.join.ActionJoinAnswer;
import fucoin.actions.join.ActionTellSupervisor;
import fucoin.actions.join.ServerActionJoin;
import fucoin.actions.persist.ActionInvokeLeave;
import fucoin.actions.persist.ActionInvokeRevive;
import fucoin.actions.transaction.ActionGetAmountAnswer;
import fucoin.actions.transaction.ActionInvokeSentMoney;
import fucoin.gui.WalletGuiControl;
import scala.concurrent.Future;

import static akka.dispatch.Futures.future;

import java.util.concurrent.ConcurrentLinkedQueue;

public class WalletImpl extends AbstractWallet {

    private ActorRef preKnownNeighbour;
    private ActorRef remoteSuperVisorActor;
    private transient WalletGuiControl gui;
    private String preKnownNeighbourName;
    private boolean isActive;
    private ConcurrentLinkedQueue<ActorRef> deferedSupervisorReceivers = new ConcurrentLinkedQueue<>();

    public WalletImpl(String name) {
        super(name);
    }

    public WalletImpl(ActorRef preKnownNeighbour, String walletName) {
        super(walletName);
        if (preKnownNeighbour != null) {
            this.preKnownNeighbourName = preKnownNeighbour.path().name();
            this.preKnownNeighbour = preKnownNeighbour;
        }
    }

    public static Props props(ActorRef preKnownNeighbour, String walletName, boolean createGUI) {
        return Props.create(new WalletCreator(preKnownNeighbour, walletName, createGUI));
    }

    /**
     * Adds amount to the current amount of FUCs in the wallet.
     *
     * @param amount value to add to current account.
     */
    public void addAmount(int amount) {
        setAmount(this.getAmount() + amount);
        addLogMsg(" My amount is now " + this.getAmount());
    }

    @Override
    public void leave() {
        getSelf().tell(new ActionInvokeLeave(), getSelf());
    }

    @Override
    public void onReceive(Object message) {

        addLogMsg(getSender().path().name() + " invokes " + getSelf().path().name() + " to do " + message.getClass().getSimpleName());
        if (message instanceof ActionInvokeRevive) {
            ((ActionInvokeRevive) message).doAction(this);
        }
        if (!isActive && !(message instanceof ActionInvokeRevive)) return;

        if (message instanceof ClientAction) {
            ((ClientAction) message).doAction(this);
        }

    }

    @Override
    public void preStart() throws Exception {

        isActive = true;

        if (gui != null) {
            String address = getAddress();
            gui.setAddress(address);
            if (address.contains("Remote@")) {
                gui.setRemote();
            }
        }

        if (preKnownNeighbour != null) {
            addKnownNeighbor(preKnownNeighbourName, preKnownNeighbour);
            preKnownNeighbour.tell(new ActionJoin(), getSelf());
            ActionJoinAnswer aja = new ActionJoinAnswer();
            aja.someNeighbors.putAll(getKnownNeighbors());
            aja.someNeighbors.put(name, getSelf());
            preKnownNeighbour.tell(aja, getSelf());

            if (this.getRemoteSuperVisorActor() != null) {
                preKnownNeighbour.tell(new ActionTellSupervisor(this.getRemoteSuperVisorActor()), self());
            }

        }
    }

    @Override
    public void postStop() throws Exception {
        leave();
        super.postStop();

    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof WalletImpl) {
            WalletImpl wobj = (WalletImpl) obj;
            return amount == wobj.getAmount() && name.equals(wobj.getName());
        }
        return false;
    }

    /**
     * Returns the amount of FUCs currently in the wallet.
     *
     * @return
     */
    public int getAmount() {
        return amount;
    }

    /**
     * Sets the amount of FUCs in the wallet to amount.
     *
     * @param amount New amount of the wallet
     */
    public void setAmount(int amount) {
        this.amount = amount;

        if (remoteSuperVisorActor != null) {
            remoteSuperVisorActor.tell(new ActionGetAmountAnswer(getAddress(), getName(), amount), getSelf());
        }
        if (gui != null) {
            gui.setAmount(this.amount);
        }
    }

    @Override
    public ActorRef getPreKnownNeighbour() {
        return preKnownNeighbour;
    }

    public void setPreKnownNeighbour(ActorRef preKnownNeighbour) {
        this.preKnownNeighbour = preKnownNeighbour;
    }

    @Override
    public ActorRef getRemoteSuperVisorActor() {
        return remoteSuperVisorActor;
    }

    public Future<ActorRef> resolveSuperVisorActor() {
        // TODO: this should return only, if getRemoteSuperVisorActor() != null
        return future(() -> getRemoteSuperVisorActor(), context().system().dispatcher());
    }

    @Override
    public void setRemoteSuperVisorActor(ActorRef remoteSuperVisorActor) {
        if (this.remoteSuperVisorActor == null) {
            this.remoteSuperVisorActor = remoteSuperVisorActor;
            this.remoteSuperVisorActor.tell(new ServerActionJoin(getName()), getSelf());
            this.tellDeferedSuperVisorReceivers(remoteSuperVisorActor);
        }
    }

    @Override
    public void deferSendOfSuperVisorActor(ActorRef destinationWallet) {
        deferedSupervisorReceivers.add(destinationWallet);
    }

    protected void tellDeferedSuperVisorReceivers(ActorRef supervisor) {
        while (deferedSupervisorReceivers.size() > 0) {
            ActorRef receiver = deferedSupervisorReceivers.poll();
            if (receiver != null) {
                receiver.tell(new ActionTellSupervisor(supervisor), self());
            }
        }
    }

    public WalletGuiControl getGui() {
        return gui;
    }

    public void setGui(WalletGuiControl gui) {
        this.gui = gui;
    }

    public void setActive(boolean isActive) {
        this.isActive = isActive;
    }

    @Override
    public boolean addKnownNeighbor(String key, ActorRef value) {
        addLogMsg(key + " is newNeighbor of " + name + "?" + !getKnownNeighbors().containsKey(key));
        if (getKnownNeighbors().containsKey(key) || key.equals(name)) {
            return false;
        }

        boolean newNeighbor = super.addKnownNeighbor(key, value);
        if (gui != null && newNeighbor) {
            gui.addKnownAddress(key);
        }
        return newNeighbor;
    }

    public void send(String address, int amount) {
        send(address, amount, null);
    }

    @Override
    public void send(String address, int amount, ActorRef observer) {
        getSelf().tell(new ActionInvokeSentMoney(address, amount, observer), getSelf());
    }

    @Override
    public void addLogMsg(String message) {
        if (gui != null) {
            gui.addLogMsg(message);
        } else {
            System.out.println(message);
        }
    }

    @Override
    public void addTransactionLogMessageSuccess(String message) {
        if (gui != null) {
            gui.addTransactionLogMessageSuccess(message);
        } else {
            System.out.println(message);
        }
    }

    @Override
    public void addTransactionLogMessageFail(String message) {
        if (gui != null) {
            gui.addTransactionLogMessageFail(message);
        } else {
            System.out.println(message);
        }
    }
}