Cleanup state handling in domain

This commit is contained in:
Manfred Karrer 2015-03-26 01:10:46 +01:00
parent 77bf67e465
commit 9936dca851
30 changed files with 314 additions and 228 deletions

View file

@ -211,8 +211,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
takerTrade.processStateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("takerTrade state = " + newValue);
String msg = "";
if (newValue.getErrorMessage() != null)
msg = "\nError message: " + newValue.getErrorMessage();
if (takerTrade.getErrorMessage() != null)
msg = "\nError message: " + takerTrade.getErrorMessage();
switch (newValue) {
case TAKE_OFFER_FEE_TX_CREATED:
@ -235,7 +235,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
break;
case PAYOUT_PUBLISHED:
break;
case UNSPECIFIC_FAULT:
case EXCEPTION:
errorMessage.set(msg);
takeOfferRequested = false;
break;

View file

@ -58,20 +58,13 @@ public class OffererTrade extends Trade implements Serializable {
public enum OffererProcessState implements ProcessState {
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
UNSPECIFIC_FAULT;
protected String errorMessage;
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getErrorMessage() {
return errorMessage;
}
UNSPECIFIC_FAULT
}
protected OffererProcessState processState;

View file

@ -58,25 +58,17 @@ public class TakerTrade extends Trade implements Serializable {
TAKE_OFFER_FEE_TX_CREATED,
TAKE_OFFER_FEE_PUBLISHED,
TAKE_OFFER_FEE_PUBLISH_FAILED,
DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED,
FIAT_PAYMENT_STARTED,
FIAT_PAYMENT_RECEIVED,
PAYOUT_PUBLISHED,
MESSAGE_SENDING_FAILED,
UNSPECIFIC_FAULT;
protected String errorMessage;
@Override
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
@Override
public String getErrorMessage() {
return errorMessage;
}
EXCEPTION
}
protected TakerProcessState processState;
@ -111,26 +103,32 @@ public class TakerTrade extends Trade implements Serializable {
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
public void setProcessState(TakerProcessState processState) {
this.processState = processState;
processStateProperty.set(processState);
if (processState == TakerProcessState.UNSPECIFIC_FAULT) {
setLifeCycleState(TakerLifeCycleState.FAILED);
disposeProtocol();
}
}
public void setLifeCycleState(TakerLifeCycleState lifeCycleState) {
this.lifeCycleState = lifeCycleState;
lifeCycleStateProperty.set(lifeCycleState);
}
public void setProcessState(TakerProcessState processState) {
this.processState = processState;
processStateProperty.set(processState);
if (processState == TakerProcessState.EXCEPTION) {
setLifeCycleState(TakerLifeCycleState.FAILED);
disposeProtocol();
}
}
public void setDepositTx(Transaction tx) {
this.depositTx = tx;
setConfidenceListener();
}
@Override
public void setThrowable(Throwable throwable) {
super.setThrowable(throwable);
setProcessState(TakerTrade.TakerProcessState.EXCEPTION);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters

View file

@ -44,9 +44,8 @@ abstract public class Trade implements Serializable {
transient protected static final Logger log = LoggerFactory.getLogger(Trade.class);
public interface ProcessState {
void setErrorMessage(String errorMessage);
String getErrorMessage();
}
public interface LifeCycleState {
@ -68,6 +67,8 @@ abstract public class Trade implements Serializable {
protected Peer tradingPeer;
protected int depthInBlocks = 0;
transient protected String errorMessage;
transient protected Throwable throwable;
transient protected ObjectProperty<Coin> tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
transient protected ObjectProperty<Fiat> tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
@ -159,6 +160,14 @@ abstract public class Trade implements Serializable {
this.payoutTx = tx;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public void setThrowable(Throwable throwable) {
this.throwable = throwable;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
@ -216,6 +225,14 @@ abstract public class Trade implements Serializable {
return tradeVolumeProperty;
}
public String getErrorMessage() {
return errorMessage;
}
public Throwable getThrowable() {
return throwable;
}
abstract public ReadOnlyObjectProperty<? extends ProcessState> processStateProperty();
abstract public ReadOnlyObjectProperty<? extends LifeCycleState> lifeCycleStateProperty();

View file

@ -57,8 +57,9 @@ public class CreateAndSignPayoutTx extends Task<OffererAsBuyerModel> {
model.taker.payoutAmount = takerPayoutAmount;
complete();
} catch (Exception e) {
failed(e);
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -46,8 +46,9 @@ public class CreateOffererDepositTxInputs extends Task<OffererAsBuyerModel> {
model.offerer.outputs = result.getOutputs();
complete();
} catch (Throwable e) {
failed(e);
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -47,6 +47,7 @@ public class ProcessPayoutTxPublishedMessage extends Task<OffererAsBuyerModel> {
complete();
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}

View file

@ -49,6 +49,7 @@ public class ProcessRequestDepositTxInputsMessage extends Task<OffererAsBuyerMod
complete();
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}

View file

@ -54,6 +54,7 @@ public class ProcessRequestOffererPublishDepositTxMessage extends Task<OffererAs
complete();
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}

View file

@ -20,6 +20,7 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.models.OffererAsBuyerModel;
@ -35,6 +36,7 @@ public class RequestTakerDepositPayment extends Task<OffererAsBuyerModel> {
@Override
protected void doRun() {
try {
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(
model.id,
model.offerer.connectedOutputsForAllInputs,
@ -54,8 +56,15 @@ public class RequestTakerDepositPayment extends Task<OffererAsBuyerModel> {
@Override
public void handleFault() {
appendToErrorMessage("Sending RequestTakerDepositPaymentMessage failed");
model.trade.setErrorMessage(errorMessage);
model.trade.setProcessState(OffererTrade.OffererProcessState.MESSAGE_SENDING_FAILED);
failed();
}
});
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -49,20 +49,22 @@ public class SendBankTransferStartedMessage extends Task<OffererAsBuyerModel> {
new SendMessageListener() {
@Override
public void handleResult() {
log.trace("Sending BankTransferInitedMessage succeeded.");
log.trace("Sending FiatTransferStartedMessage succeeded.");
model.trade.setProcessState(OffererTrade.OffererProcessState.FIAT_PAYMENT_STARTED);
complete();
}
@Override
public void handleFault() {
failed("Sending BankTransferInitedMessage failed.");
model.trade.setProcessState(OffererTrade.OffererProcessState.UNSPECIFIC_FAULT);
appendToErrorMessage("Sending FiatTransferStartedMessage failed");
model.trade.setErrorMessage(errorMessage);
model.trade.setProcessState(OffererTrade.OffererProcessState.MESSAGE_SENDING_FAILED);
failed();
}
});
} catch (Throwable t) {
failed("Sending BankTransferInitedMessage failed.");
model.trade.setProcessState(OffererTrade.OffererProcessState.UNSPECIFIC_FAULT);
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -20,6 +20,7 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.models.OffererAsBuyerModel;
@ -35,6 +36,7 @@ public class SendDepositTxToTaker extends Task<OffererAsBuyerModel> {
@Override
protected void doRun() {
try {
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(model.id, model.trade.getDepositTx());
model.messageService.sendMessage(model.trade.getTradingPeer(), tradeMessage, new SendMessageListener() {
@ -46,8 +48,15 @@ public class SendDepositTxToTaker extends Task<OffererAsBuyerModel> {
@Override
public void handleFault() {
failed("Sending DepositTxPublishedMessage failed.");
appendToErrorMessage("Sending DepositTxPublishedMessage failed");
model.trade.setErrorMessage(errorMessage);
model.trade.setProcessState(OffererTrade.OffererProcessState.MESSAGE_SENDING_FAILED);
failed();
}
});
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -66,11 +66,13 @@ public class SignAndPublishDepositTx extends Task<OffererAsBuyerModel> {
@Override
public void onFailure(@NotNull Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
});
} catch (Exception e) {
failed(e);
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -36,6 +36,7 @@ public class VerifyAndSignContract extends Task<OffererAsBuyerModel> {
@Override
protected void doRun() {
try {
Trade trade = model.trade;
Contract contract = new Contract(
@ -57,5 +58,9 @@ public class VerifyAndSignContract extends Task<OffererAsBuyerModel> {
trade.setTakerContractSignature(model.taker.contractSignature);
complete();
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -33,6 +33,7 @@ public class VerifyTakeOfferFeePayment extends Task<OffererAsBuyerModel> {
@Override
protected void doRun() {
try {
//TODO mocked yet, need a confidence listeners
int numOfPeersSeenTx = model.walletService.getNumOfPeersSeenTx(model.getTakeOfferFeeTxId());
/* if (numOfPeersSeenTx > 2) {
@ -40,5 +41,9 @@ public class VerifyTakeOfferFeePayment extends Task<OffererAsBuyerModel> {
}*/
complete();
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -33,6 +33,7 @@ public class VerifyTakerAccount extends Task<OffererAsBuyerModel> {
@Override
protected void doRun() {
try {
//TODO mocked yet
if (model.blockChainService.verifyAccountRegistration()) {
if (model.blockChainService.isAccountBlackListed(model.taker.accountId, model.taker.fiatAccount)) {
@ -46,5 +47,10 @@ public class VerifyTakerAccount extends Task<OffererAsBuyerModel> {
else {
failed("Account registration validation for peer failed.");
}
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -54,18 +54,16 @@ public class BroadcastTakeOfferFeeTx extends Task<TakerAsSellerModel> {
@Override
public void onFailure(@NotNull Throwable t) {
appendToErrorMessage("Take offer fee payment failed. Maybe your network connection was lost. Please try again.");
model.trade.setErrorMessage(errorMessage);
model.trade.setProcessState(TakerTrade.TakerProcessState.TAKE_OFFER_FEE_PUBLISH_FAILED);
failed(t);
}
});
} catch (Exception e) {
appendToErrorMessage("Take offer fee payment failed. Maybe your network connection was lost. Please try again.");
appendToErrorMessage(e.getMessage());
model.trade.setProcessState(TakerTrade.TakerProcessState.UNSPECIFIC_FAULT);
failed(e);
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -36,6 +36,7 @@ public class CreateAndSignContract extends Task<TakerAsSellerModel> {
@Override
protected void doRun() {
try {
Trade trade = model.trade;
Contract contract = new Contract(
model.offer,
@ -55,5 +56,9 @@ public class CreateAndSignContract extends Task<TakerAsSellerModel> {
trade.setTakerContractSignature(signature);
complete();
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -43,12 +43,9 @@ public class CreateTakeOfferFeeTx extends Task<TakerAsSellerModel> {
model.trade.setProcessState(TakerTrade.TakerProcessState.TAKE_OFFER_FEE_TX_CREATED);
complete();
} catch (Exception e) {
appendToErrorMessage(e.getMessage());
model.trade.setProcessState(TakerTrade.TakerProcessState.UNSPECIFIC_FAULT);
failed(e);
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -47,6 +47,7 @@ public class ProcessDepositTxPublishedMessage extends Task<TakerAsSellerModel> {
complete();
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}

View file

@ -50,7 +50,7 @@ public class ProcessFiatTransferStartedMessage extends Task<TakerAsSellerModel>
complete();
} catch (Throwable t) {
model.trade.setProcessState(TakerTrade.TakerProcessState.UNSPECIFIC_FAULT);
model.trade.setThrowable(t);
failed(t);
}
}

View file

@ -52,6 +52,7 @@ public class ProcessRequestTakerDepositPaymentMessage extends Task<TakerAsSeller
complete();
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}

View file

@ -20,6 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.models.TakerAsSellerModel;
@ -35,6 +36,7 @@ public class SendPayoutTxToOfferer extends Task<TakerAsSellerModel> {
@Override
protected void doRun() {
try {
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(model.id, model.getPayoutTx());
model.messageService.sendMessage(model.trade.getTradingPeer(),
tradeMessage,
@ -49,8 +51,15 @@ public class SendPayoutTxToOfferer extends Task<TakerAsSellerModel> {
@Override
public void handleFault() {
failed("Sending PayoutTxPublishedMessage failed.");
appendToErrorMessage("Sending PayoutTxPublishedMessage failed");
model.trade.setErrorMessage(errorMessage);
model.trade.setProcessState(TakerTrade.TakerProcessState.MESSAGE_SENDING_FAILED);
failed();
}
});
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -40,12 +40,12 @@ public class SendRequestDepositTxInputsMessage extends Task<TakerAsSellerModel>
@Override
protected void doRun() {
try {
RequestDepositTxInputsMessage msg = new RequestDepositTxInputsMessage(
model.id,
model.getTakeOfferFeeTx().getHashAsString(),
model.trade.getTradeAmount(),
model.taker.tradeWalletPubKey
);
model.taker.tradeWalletPubKey);
model.messageService.sendMessage(model.trade.getTradingPeer(), msg, new SendMessageListener() {
@Override
@ -56,6 +56,7 @@ public class SendRequestDepositTxInputsMessage extends Task<TakerAsSellerModel>
@Override
public void handleFault() {
log.warn("Sending TakeOfferFeePayedMessage failed. We try a second time.");
// Take offer fee is already paid, so we need to try to get that trade to succeed.
// We try to repeat once and if that fails as well we persist the state for a later retry.
if (retryCounter == 0) {
@ -63,15 +64,20 @@ public class SendRequestDepositTxInputsMessage extends Task<TakerAsSellerModel>
Platform.runLater(SendRequestDepositTxInputsMessage.this::doRun);
}
else {
appendToErrorMessage("Sending TakeOfferFeePayedMessage to offerer failed. Maybe the network connection was lost or the offerer lost his " +
"connection. " +
"We persisted the state of the trade, please try again later or cancel that trade.");
appendToErrorMessage("Sending TakeOfferFeePayedMessage to offerer failed. Maybe the network connection was " +
"lost or the offerer lost his connection. We persisted the state of the trade, please try again later " +
"or cancel that trade.");
model.trade.setErrorMessage(errorMessage);
model.trade.setProcessState(TakerTrade.TakerProcessState.MESSAGE_SENDING_FAILED);
failed();
}
}
});
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -20,6 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.listener.SendMessageListener;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.messages.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.taker.models.TakerAsSellerModel;
@ -35,6 +36,7 @@ public class SendSignedTakerDepositTx extends Task<TakerAsSellerModel> {
@Override
protected void doRun() {
try {
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(
model.id,
model.taker.fiatAccount,
@ -57,8 +59,16 @@ public class SendSignedTakerDepositTx extends Task<TakerAsSellerModel> {
@Override
public void handleFault() {
failed("Sending RequestOffererDepositPublicationMessage failed");
appendToErrorMessage("Sending RequestOffererDepositPublicationMessage failed");
model.trade.setErrorMessage(errorMessage);
model.trade.setProcessState(TakerTrade.TakerProcessState.MESSAGE_SENDING_FAILED);
failed();
}
});
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -62,11 +62,13 @@ public class SignAndPublishPayoutTx extends Task<TakerAsSellerModel> {
@Override
public void onFailure(@NotNull Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
});
} catch (Throwable e) {
failed(e);
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -22,7 +22,6 @@ import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.protocol.trade.taker.models.TakerAsSellerModel;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.VerificationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -43,7 +42,8 @@ public class TakerCommitDepositTx extends Task<TakerAsSellerModel> {
model.trade.setDepositTx(depositTx);
complete();
} catch (VerificationException t) {
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}

View file

@ -21,7 +21,6 @@ import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.taker.models.TakerAsSellerModel;
import org.bitcoinj.core.Coin;
@ -58,12 +57,9 @@ public class TakerCreatesAndSignsDepositTx extends Task<TakerAsSellerModel> {
model.taker.preparedDepositTx = result.getDepositTx();
complete();
} catch (Exception e) {
TakerTrade.TakerProcessState processState = TakerTrade.TakerProcessState.UNSPECIFIC_FAULT;
processState.setErrorMessage(errorMessage);
model.trade.setProcessState(processState);
failed(e);
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -33,11 +33,16 @@ public class VerifyOfferFeePayment extends Task<TakerAsSellerModel> {
@Override
protected void doRun() {
try {
//TODO impl. missing
int numOfPeersSeenTx = model.walletService.getNumOfPeersSeenTx(model.getTakeOfferFeeTx().getHashAsString());
/* if (numOfPeersSeenTx > 2) {
resultHandler.handleResult();
}*/
complete();
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}

View file

@ -33,6 +33,7 @@ public class VerifyOffererAccount extends Task<TakerAsSellerModel> {
@Override
protected void doRun() {
try {
if (model.blockChainService.verifyAccountRegistration()) {
if (model.blockChainService.isAccountBlackListed(model.offerer.accountId, model.offerer.fiatAccount)) {
failed("Taker is blacklisted.");
@ -44,5 +45,9 @@ public class VerifyOffererAccount extends Task<TakerAsSellerModel> {
else {
failed("Account registration validation for peer faultHandler.onFault.");
}
} catch (Throwable t) {
model.trade.setThrowable(t);
failed(t);
}
}
}