package org.nightlabs.jfire.trade.ui.transfer;
import java.rmi.RemoteException;
import java.util.LinkedList;
import java.util.List;
import javax.naming.NamingException;
import javax.security.auth.login.LoginException;
import org.nightlabs.ModuleException;
import org.nightlabs.datastructure.Pair;
import org.nightlabs.jfire.accounting.pay.PaymentController;
import org.nightlabs.jfire.accounting.pay.PaymentData;
import org.nightlabs.jfire.store.deliver.DeliveryController;
import org.nightlabs.jfire.store.deliver.DeliveryData;
import org.nightlabs.jfire.trade.ui.transfer.deliver.ClientDeliveryProcessor;
import org.nightlabs.jfire.trade.ui.transfer.deliver.DeliveryControllerImpl;
import org.nightlabs.jfire.trade.ui.transfer.pay.ClientPaymentProcessor;
import org.nightlabs.jfire.trade.ui.transfer.pay.PaymentControllerImpl;
import org.nightlabs.jfire.trade.ui.transfer.wizard.TransferWizardUtil;
import org.nightlabs.jfire.transfer.TransferController;
import org.nightlabs.jfire.transfer.TransferData;
public class TransferCoordinator {
private List<PaymentData> paymentDatas;
private List<DeliveryData> deliveryDatas;
public TransferCoordinator() {
}
public boolean payAndDeliver(
List<Pair<PaymentData, ClientPaymentProcessor>> paymentTuples,
List<Pair<DeliveryData, ClientDeliveryProcessor>> deliveryTuples)
throws RemoteException, LoginException, NamingException, ModuleException
{
PaymentController paymentController = null;
DeliveryController deliveryController = null;
// prepare PaymentControllerImpl
if (paymentTuples != null)
paymentController = new PaymentControllerImpl(paymentTuples);
else
// if no payment is to be done, assign a noop instance to avoid endless if (paymentController == null) checks
paymentController = new DummyPaymentController();
// prepare DeliveryControllerImpl
if (deliveryTuples != null)
deliveryController = new DeliveryControllerImpl(deliveryTuples);
else
// if no delivery is to be done, assign a noop instance to avoid endless if (deliveryController == null) checks
deliveryController = new DummyDeliveryController();
performStages(deliveryController, paymentController);
this.paymentDatas = paymentController.getTransferDatas();
this.deliveryDatas = deliveryController.getTransferDatas();
// if (paymentWizard != null) {
// if (payment.isPostponed())
// payment.clearPending();
//
// if (payment.isPending() || payment.isFailed())
// return false;
// }
// TODO check both: delivery (only if deliveryWizard != null)
// TODO in case of an error, a detailed status message showing all payments/deliveries should be shown
// if (paymentWizard != null) {
// // If we come here, payment was successful
//
// if (bookInvoiceMode == BOOK_INVOICE_MODE_AFTER_SUCCESSFUL_PAYMENT) {
// try {
// accountingManager.bookInvoices(paymentWizard.getInvoiceIDs(), true, true);
// } catch (Throwable t) {
// throw new ModuleException("Payment was successful, but book failed!", t);
// }
// }
// } // if (paymentWizard != null) {
// return true;
// Daniel: moved failed check from ErrorDialog here
boolean paymentsFailed = TransferWizardUtil.isPaymentsFailed(paymentDatas);
boolean deliveriesFailed = TransferWizardUtil.isDeliveriesFailed(deliveryDatas);
return !(paymentsFailed || deliveriesFailed);
}
public void performStages(DeliveryController deliveryController, PaymentController paymentController) throws LoginException {
boolean skipServerPayment = false;
boolean skipServerDelivery = false;
///////////
// BEGIN //
///////////
// if the client approve failed on ALL client payments, we don't do anything
// in the server, but call the client's payEnd to allow clean-up.
skipServerPayment = !paymentController.clientBegin();
// if the client approve failed for ALL deliveries, we don't do anything
// in the server, but call the client's deliverEnd to allow clean-up.
skipServerDelivery = !deliveryController.clientBegin();
if (skipServerDelivery)
deliveryController.skipServerStages();
if (skipServerPayment)
paymentController.skipServerStages();
// TODO perform Server-Payment and -Delivery in one step if both must be done
deliveryController.serverBegin();
paymentController.serverBegin();
if (paymentController.isRollbackRequired() || deliveryController.isRollbackRequired()) {
paymentController.forceRollback();
deliveryController.forceRollback();
}
////////////
// DOWORK //
////////////
deliveryController.clientDoWork();
paymentController.clientDoWork();
deliveryController.serverDoWork();
paymentController.serverDoWork();
if (paymentController.isRollbackRequired() || deliveryController.isRollbackRequired()) {
paymentController.forceRollback();
deliveryController.forceRollback();
}
/////////
// END //
/////////
deliveryController.clientEnd();
paymentController.clientEnd();
deliveryController.serverEnd();
paymentController.serverEnd();
////////////
// VERIFY //
////////////
paymentController.verifyData();
deliveryController.verifyData();
}
public List<PaymentData> getPaymentDatas() {
return paymentDatas;
}
public List<DeliveryData> getDeliveryDatas() {
return deliveryDatas;
}
}
/**
* A {@link DeliveryController} that does absolutely nothing.
*
* @author Tobias Langner <!-- tobias[dot]langner[at]nightlabs[dot]de -->
*/
class DummyController<D extends TransferData> implements TransferController<D> {
public boolean clientBegin() { return true; }
public void clientDoWork() {}
public void clientEnd() {}
public boolean isRollbackRequired() {
return rollbackRequired;
}
public void serverBegin() {}
public void serverDoWork() {}
public void serverEnd() {}
public void verifyData() {}
private boolean rollbackRequired = false;
public void forceRollback() {
rollbackRequired = true;
}
public List<D> getTransferDatas() { return new LinkedList<D>(); }
public void skipServerStages() {}
}
class DummyDeliveryController extends DummyController<DeliveryData> implements DeliveryController {
}
class DummyPaymentController extends DummyController<PaymentData> implements PaymentController {
}