package org.nightlabs.jfire.trade.ui.transfer.pay; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.nightlabs.datastructure.Pair; import org.nightlabs.jfire.accounting.pay.AbstractPaymentController; import org.nightlabs.jfire.accounting.pay.Payment; import org.nightlabs.jfire.accounting.pay.PaymentData; import org.nightlabs.jfire.accounting.pay.PaymentException; import org.nightlabs.jfire.accounting.pay.PaymentResult; import org.nightlabs.jfire.accounting.pay.id.PaymentID; import org.nightlabs.jfire.idgenerator.IDGenerator; /** * A controller for the different stages of the payment process as described in the * <a href="https://www.jfire.org/modules/phpwiki/index.php/WorkflowPaymentAndDelivery">JFire Wiki</a>. * * @author Tobias Langner <!-- tobias[dot]langner[at]nightlabs[dot]de --> */ public class PaymentControllerImpl extends AbstractPaymentController { private Map<PaymentData, ClientPaymentProcessor> paymentProcessorMap; /** * Initialises a PaymentControllerImpl with the list of tuples of the type ({@link PaymentData}, {@link ClientPaymentProcessor}). The controller * will process all given {@link PaymentData}s using the respective {@link ClientPaymentProcessor} in the client stages. * @param paymentTuples A list of tuples of {@link PaymentData} and a corresponding {@link ClientPaymentProcessor}. */ public PaymentControllerImpl(List<Pair<PaymentData, ClientPaymentProcessor>> paymentTuples) { super(getPaymentDatas(paymentTuples)); paymentProcessorMap = new HashMap<PaymentData, ClientPaymentProcessor>(); for (Pair<PaymentData, ClientPaymentProcessor> tuple : paymentTuples) { paymentProcessorMap.put(tuple.getFirst(), tuple.getSecond()); } } private static List<PaymentData> getPaymentDatas(List<Pair<PaymentData, ClientPaymentProcessor>> paymentTuples) { List<PaymentData> paymentDatas = new LinkedList<PaymentData>(); for (Pair<PaymentData, ClientPaymentProcessor> tuple : paymentTuples) { PaymentData data = tuple.getFirst(); paymentDatas.add(data); } return paymentDatas; } /* (non-Javadoc) * @see org.nightlabs.jfire.trade.ui.transfer.pay.PaymentController#clientBegin() */ @Override public boolean _clientBegin() { boolean allFailed = true; ClientPaymentProcessor clientPaymentProcessor = null; Payment payment = null; ArrayList<PaymentResult> payBeginClientResults = new ArrayList<PaymentResult>(getTransferDatas().size()); for (PaymentData paymentData : getTransferDatas()) { clientPaymentProcessor = paymentProcessorMap.get(paymentData); payment = paymentData.getPayment(); try { PaymentResult payBeginClientResult = clientPaymentProcessor.payBegin(); if (payBeginClientResult == null) payBeginClientResult = new PaymentResult( PaymentResult.CODE_APPROVED_NO_EXTERNAL, (String)null, (Throwable)null); payment.setPayBeginClientResult(payBeginClientResult); } catch (PaymentException x) { payment.setPayBeginClientResult(x.getPaymentResult()); } catch (Throwable t) { PaymentResult payBeginClientResult = new PaymentResult(IDGenerator.getOrganisationID(), t); payment.setPayBeginClientResult(payBeginClientResult); } payBeginClientResults.add(payment.getPayBeginClientResult()); allFailed &= payment.isFailed(); } setLastStageResults(payBeginClientResults); return !allFailed; } /* (non-Javadoc) * @see org.nightlabs.jfire.trade.ui.transfer.pay.PaymentController#clientDoWork() */ @Override public void _clientDoWork() { List<PaymentID> paymentIDs = new ArrayList<PaymentID>(getTransferDatas().size()); ArrayList<PaymentResult> payDoWorkClientResults = new ArrayList<PaymentResult>(getTransferDatas().size()); ClientPaymentProcessor clientPaymentProcessor = null; for (PaymentData paymentData : getTransferDatas()) { Payment payment = paymentData.getPayment(); clientPaymentProcessor = paymentProcessorMap.get(paymentData); paymentIDs.add(PaymentID.create(payment.getOrganisationID(), payment.getPaymentID())); try { PaymentResult payDoWorkClientResult = clientPaymentProcessor.payDoWork(); if (payDoWorkClientResult == null) payDoWorkClientResult = new PaymentResult( PaymentResult.CODE_PAID_NO_EXTERNAL, (String)null, (Throwable)null); payment.setPayDoWorkClientResult(payDoWorkClientResult); } catch (PaymentException x) { payment.setPayDoWorkClientResult(x.getPaymentResult()); } catch (Throwable t) { PaymentResult payDoWorkClientResult = new PaymentResult(IDGenerator.getOrganisationID(), t); payment.setPayDoWorkClientResult(payDoWorkClientResult); } payDoWorkClientResults.add(payment.getPayDoWorkClientResult()); } // setTransferIDs(paymentIDs); setLastStageResults(payDoWorkClientResults); } /* (non-Javadoc) * @see org.nightlabs.jfire.trade.ui.transfer.pay.PaymentController#clientEnd() */ @Override public void _clientEnd() { ClientPaymentProcessor clientPaymentProcessor = null; Payment payment = null; List<PaymentResult> payEndClientResults = new ArrayList<PaymentResult>(getTransferDatas().size()); for (PaymentData paymentData : getTransferDatas()) { payment = paymentData.getPayment(); clientPaymentProcessor = paymentProcessorMap.get(paymentData); try { PaymentResult payEndClientResult = clientPaymentProcessor.payEnd(); if (payEndClientResult == null) { if (payment.isForceRollback() || payment.isFailed()) { payEndClientResult = new PaymentResult( PaymentResult.CODE_ROLLED_BACK_NO_EXTERNAL, (String)null, (Throwable)null); } else { payEndClientResult = new PaymentResult( PaymentResult.CODE_COMMITTED_NO_EXTERNAL, (String)null, (Throwable)null); } } payment.setPayEndClientResult(payEndClientResult); } catch (PaymentException x) { payment.setPayEndClientResult(x.getPaymentResult()); } catch (Throwable t) { PaymentResult payEndClientResult = new PaymentResult(IDGenerator.getOrganisationID(), t); payment.setPayEndClientResult(payEndClientResult); } payEndClientResults.add(payment.getPayEndClientResult()); } setLastStageResults(payEndClientResults); } /* (non-Javadoc) * @see org.nightlabs.jfire.trade.ui.transfer.pay.PaymentController#verifyData() */ @Override public void verifyData() { for (PaymentData paymentData : getTransferDatas()) { Payment payment = paymentData.getPayment(); if ((payment.getPayBeginClientResult() != null && payment.getPayBeginClientResult().isRolledBack()) || (payment.getPayBeginServerResult() != null && payment.getPayBeginServerResult().isRolledBack()) || (payment.getPayDoWorkClientResult() != null && payment.getPayDoWorkClientResult().isRolledBack()) || (payment.getPayDoWorkServerResult() != null && payment.getPayDoWorkServerResult().isRolledBack()) || (payment.getPayEndClientResult() != null && payment.getPayEndClientResult().isRolledBack()) || (payment.getPayEndServerResult() != null && payment.getPayEndServerResult().isRolledBack())) payment.setRollbackStatus(Payment.ROLLBACK_STATUS_DONE_NORMAL); // TODO this might differ from the value on the server - do we better download the data from the server? } } }