Search in sources :

Example 1 with OperationException

use of org.killbill.automaton.OperationException in project killbill by killbill.

the class PluginControlPaymentAutomatonRunner method run.

public Payment run(final State state, final boolean isApiPayment, final Boolean isSuccess, final TransactionType transactionType, final ControlOperation controlOperation, final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID paymentId, @Nullable final String paymentExternalKey, @Nullable final UUID transactionId, final String paymentTransactionExternalKey, @Nullable final BigDecimal amount, @Nullable final Currency currency, final Iterable<PluginProperty> properties, @Nullable final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
    final PaymentStateControlContext paymentStateContext = createContext(isApiPayment, isSuccess, transactionType, account, paymentMethodId, paymentId, paymentExternalKey, transactionId, paymentTransactionExternalKey, amount, currency, properties, paymentControlPluginNames, callContext, internalCallContext);
    try {
        final OperationCallback callback = createOperationCallback(controlOperation, paymentStateContext);
        final LeavingStateCallback leavingStateCallback = new DefaultControlInitiated(this, paymentStateContext, paymentDao, paymentControlStateMachineHelper.getInitialState(), paymentControlStateMachineHelper.getRetriedState(), transactionType);
        final EnteringStateCallback enteringStateCallback = new DefaultControlCompleted(this, paymentStateContext, paymentControlStateMachineHelper.getRetriedState(), retryServiceScheduler);
        state.runOperation(paymentControlStateMachineHelper.getOperation(), callback, enteringStateCallback, leavingStateCallback);
    } catch (final MissingEntryException e) {
        throw new PaymentApiException(e.getCause(), ErrorCode.PAYMENT_INTERNAL_ERROR, MoreObjects.firstNonNull(e.getMessage(), ""));
    } catch (final OperationException e) {
        if (e.getCause() instanceof PaymentApiException) {
            throw (PaymentApiException) e.getCause();
        // If the control plugin tries to pass us back a PaymentApiException we throw it
        } else if (e.getCause() instanceof PaymentControlApiException && e.getCause().getCause() instanceof PaymentApiException) {
            throw (PaymentApiException) e.getCause().getCause();
        } else if (e.getCause() != null || paymentStateContext.getResult() == null) {
            throw new PaymentApiException(e.getCause(), ErrorCode.PAYMENT_INTERNAL_ERROR, MoreObjects.firstNonNull(e.getMessage(), ""));
        }
    }
    // we don't throw, and return the failed Payment instead to be consistent with what happens when we don't go through control api.
    return paymentStateContext.getResult();
}
Also used : DefaultControlInitiated(org.killbill.billing.payment.core.sm.control.DefaultControlInitiated) OperationCallback(org.killbill.automaton.Operation.OperationCallback) DefaultControlCompleted(org.killbill.billing.payment.core.sm.control.DefaultControlCompleted) MissingEntryException(org.killbill.automaton.MissingEntryException) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) LeavingStateCallback(org.killbill.automaton.State.LeavingStateCallback) EnteringStateCallback(org.killbill.automaton.State.EnteringStateCallback) OperationException(org.killbill.automaton.OperationException) PaymentControlApiException(org.killbill.billing.control.plugin.api.PaymentControlApiException) PaymentStateControlContext(org.killbill.billing.payment.core.sm.control.PaymentStateControlContext)

Example 2 with OperationException

use of org.killbill.automaton.OperationException in project killbill by killbill.

the class TestPluginOperation method runPluginOperationInBackground.

private AtomicBoolean runPluginOperationInBackground(final PaymentOperation pluginOperation, final CallbackTest callback, final boolean shouldFailBecauseOfLockFailure) throws Exception {
    final AtomicBoolean threadRunning = new AtomicBoolean(false);
    final AtomicBoolean threadHasRun = new AtomicBoolean(false);
    final Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            threadRunning.set(true);
            try {
                if (shouldFailBecauseOfLockFailure) {
                    try {
                        pluginOperation.dispatchWithAccountLockAndTimeout(PLUGIN_NAME_PLACEHOLDER, callback);
                        Assert.fail();
                    } catch (final OperationException e) {
                        Assert.assertTrue(e.getCause() instanceof PaymentApiException);
                        // No better error code for lock failures...
                        Assert.assertEquals(((PaymentApiException) e.getCause()).getCode(), ErrorCode.PAYMENT_INTERNAL_ERROR.getCode());
                    }
                } else {
                    try {
                        pluginOperation.dispatchWithAccountLockAndTimeout(PLUGIN_NAME_PLACEHOLDER, callback);
                    } catch (final OperationException e) {
                        Assert.fail(e.getMessage());
                    }
                }
            } finally {
                threadHasRun.set(true);
            }
        }
    });
    t1.start();
    // Make sure the thread has started
    Awaitility.await().untilTrue(threadRunning);
    return threadHasRun;
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) OperationException(org.killbill.automaton.OperationException)

Example 3 with OperationException

use of org.killbill.automaton.OperationException in project killbill by killbill.

the class TestPluginOperation method testOperationThrowsRuntimeException.

@Test(groups = "fast")
public void testOperationThrowsRuntimeException() throws Exception {
    final CallbackTest callback = new CallbackTest(new NullPointerException("Expected for the test"));
    final PaymentOperation pluginOperation = getPluginOperation();
    try {
        pluginOperation.dispatchWithAccountLockAndTimeout(PLUGIN_NAME_PLACEHOLDER, callback);
        Assert.fail();
    } catch (final OperationException e) {
        Assert.assertEquals(e.getOperationResult(), OperationResult.EXCEPTION);
        Assert.assertTrue(e.getCause() instanceof PaymentApiException);
        Assert.assertTrue(e.getCause().getCause() instanceof NullPointerException);
    }
}
Also used : PaymentOperation(org.killbill.billing.payment.core.sm.payments.PaymentOperation) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) OperationException(org.killbill.automaton.OperationException) Test(org.testng.annotations.Test)

Example 4 with OperationException

use of org.killbill.automaton.OperationException in project killbill by killbill.

the class OperationControlCallback method doOperationCallback.

@Override
public OperationResult doOperationCallback() throws OperationException {
    final List<String> pluginNameList = paymentStateControlContext.getPaymentControlPluginNames();
    final String pluginNames = JOINER.join(pluginNameList);
    return dispatchWithAccountLockAndTimeout(pluginNames, new DispatcherCallback<PluginDispatcherReturnType<OperationResult>, OperationException>() {

        @Override
        public PluginDispatcherReturnType<OperationResult> doOperation() throws OperationException {
            final Account account = paymentStateContext.getAccount();
            final UUID accountId = account != null ? account.getId() : null;
            final PaymentControlContext paymentControlContext = new DefaultPaymentControlContext(accountId, paymentStateContext.getPaymentMethodId(), paymentStateControlContext.getOriginalPaymentPluginName(), paymentStateControlContext.getAttemptId(), paymentStateContext.getPaymentId(), paymentStateContext.getPaymentExternalKey(), paymentStateContext.getTransactionId(), paymentStateContext.getPaymentTransactionExternalKey(), PaymentApiType.PAYMENT_TRANSACTION, paymentStateContext.getTransactionType(), null, paymentStateContext.getAmount(), paymentStateContext.getCurrency(), paymentStateControlContext.getProcessedAmount(), paymentStateControlContext.getProcessedCurrency(), paymentStateControlContext.isApiPayment(), paymentStateContext.getCallContext());
            try {
                executePluginPriorCalls(paymentStateControlContext.getPaymentControlPluginNames(), paymentControlContext);
            } catch (final PaymentControlApiAbortException e) {
                // Transition to ABORTED
                final PaymentApiException paymentAbortedException = new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_API_ABORTED, e.getPluginName());
                throw new OperationException(paymentAbortedException, OperationResult.EXCEPTION);
            } catch (final PaymentControlApiException e) {
                // Transition to ABORTED and throw PaymentControlApiException to caller.
                throw new OperationException(e, OperationResult.EXCEPTION);
            }
            final boolean success;
            try {
                final Payment result = doCallSpecificOperationCallback();
                ((PaymentStateControlContext) paymentStateContext).setResult(result);
                final PaymentTransaction transaction = ((PaymentStateControlContext) paymentStateContext).getCurrentTransaction();
                success = transaction.getTransactionStatus() == TransactionStatus.SUCCESS || transaction.getTransactionStatus() == TransactionStatus.PENDING;
                final PaymentControlContext updatedPaymentControlContext = new DefaultPaymentControlContext(accountId, paymentStateContext.getPaymentMethodId(), null, paymentStateControlContext.getAttemptId(), result.getId(), result.getExternalKey(), transaction.getId(), paymentStateContext.getPaymentTransactionExternalKey(), PaymentApiType.PAYMENT_TRANSACTION, paymentStateContext.getTransactionType(), null, transaction.getAmount(), transaction.getCurrency(), transaction.getProcessedAmount(), transaction.getProcessedCurrency(), paymentStateControlContext.isApiPayment(), paymentStateContext.getCallContext());
                if (success) {
                    executePluginOnSuccessCalls(paymentStateControlContext.getPaymentControlPluginNames(), updatedPaymentControlContext);
                    return PluginDispatcher.createPluginDispatcherReturnType(OperationResult.SUCCESS);
                } else {
                    throw new OperationException(null, executePluginOnFailureCallsAndSetRetryDate(updatedPaymentControlContext));
                }
            } catch (final PaymentApiException e) {
                // Wrap PaymentApiException, and throw a new OperationException with an ABORTED/FAILURE state based on the retry result.
                throw new OperationException(e, executePluginOnFailureCallsAndSetRetryDate(paymentControlContext));
            } catch (final RuntimeException e) {
                // Attempts to set the retry date in context if needed.
                throw new OperationException(e, executePluginOnFailureCallsAndSetRetryDate(paymentControlContext));
            }
        }
    });
}
Also used : PluginDispatcherReturnType(org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType) Account(org.killbill.billing.account.api.Account) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) PaymentControlApiException(org.killbill.billing.control.plugin.api.PaymentControlApiException) PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) Payment(org.killbill.billing.payment.api.Payment) DefaultPaymentControlContext(org.killbill.billing.payment.core.sm.control.ControlPluginRunner.DefaultPaymentControlContext) PaymentControlContext(org.killbill.billing.control.plugin.api.PaymentControlContext) DefaultPaymentControlContext(org.killbill.billing.payment.core.sm.control.ControlPluginRunner.DefaultPaymentControlContext) UUID(java.util.UUID) OperationException(org.killbill.automaton.OperationException)

Example 5 with OperationException

use of org.killbill.automaton.OperationException in project killbill by killbill.

the class PaymentAutomatonRunner method runStateMachineOperation.

private void runStateMachineOperation(final String initialStateName, final TransactionType transactionType, final LeavingStateCallback leavingStateCallback, final OperationCallback operationCallback, final EnteringStateCallback enteringStateCallback, final Boolean includeDeletedPaymentMethod, final PaymentStateContext paymentStateContext, final PaymentAutomatonDAOHelper daoHelper) throws PaymentApiException {
    try {
        final StateMachineConfig stateMachineConfig = paymentSMHelper.getStateMachineConfig(daoHelper.getPaymentProviderPluginName(includeDeletedPaymentMethod), paymentStateContext.getInternalCallContext());
        final StateMachine initialStateMachine = stateMachineConfig.getStateMachineForState(initialStateName);
        final State initialState = initialStateMachine.getState(initialStateName);
        final Operation operation = paymentSMHelper.getOperationForTransaction(stateMachineConfig, transactionType);
        initialState.runOperation(operation, operationCallback, enteringStateCallback, leavingStateCallback);
    } catch (final MissingEntryException e) {
        throw new PaymentApiException(e.getCause(), ErrorCode.PAYMENT_INVALID_OPERATION, transactionType, initialStateName);
    } catch (final OperationException e) {
        if (e.getCause() == null) {
            throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, MoreObjects.firstNonNull(e.getMessage(), ""));
        } else if (e.getCause() instanceof PaymentApiException) {
            throw (PaymentApiException) e.getCause();
        } else {
            throw new PaymentApiException(e.getCause(), ErrorCode.PAYMENT_INTERNAL_ERROR, MoreObjects.firstNonNull(e.getMessage(), ""));
        }
    }
}
Also used : StateMachine(org.killbill.automaton.StateMachine) State(org.killbill.automaton.State) StateMachineConfig(org.killbill.automaton.StateMachineConfig) MissingEntryException(org.killbill.automaton.MissingEntryException) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) PurchaseOperation(org.killbill.billing.payment.core.sm.payments.PurchaseOperation) RefundOperation(org.killbill.billing.payment.core.sm.payments.RefundOperation) AuthorizeOperation(org.killbill.billing.payment.core.sm.payments.AuthorizeOperation) VoidOperation(org.killbill.billing.payment.core.sm.payments.VoidOperation) Operation(org.killbill.automaton.Operation) CreditOperation(org.killbill.billing.payment.core.sm.payments.CreditOperation) ChargebackOperation(org.killbill.billing.payment.core.sm.payments.ChargebackOperation) CaptureOperation(org.killbill.billing.payment.core.sm.payments.CaptureOperation) OperationException(org.killbill.automaton.OperationException)

Aggregations

OperationException (org.killbill.automaton.OperationException)12 PaymentApiException (org.killbill.billing.payment.api.PaymentApiException)10 MissingEntryException (org.killbill.automaton.MissingEntryException)4 PaymentControlApiException (org.killbill.billing.control.plugin.api.PaymentControlApiException)4 UUID (java.util.UUID)3 OperationCallback (org.killbill.automaton.Operation.OperationCallback)3 EnteringStateCallback (org.killbill.automaton.State.EnteringStateCallback)3 LeavingStateCallback (org.killbill.automaton.State.LeavingStateCallback)3 DefaultControlCompleted (org.killbill.billing.payment.core.sm.control.DefaultControlCompleted)3 PaymentTransactionModelDao (org.killbill.billing.payment.dao.PaymentTransactionModelDao)3 Account (org.killbill.billing.account.api.Account)2 PaymentControlContext (org.killbill.billing.control.plugin.api.PaymentControlContext)2 Payment (org.killbill.billing.payment.api.Payment)2 DefaultPaymentControlContext (org.killbill.billing.payment.core.sm.control.ControlPluginRunner.DefaultPaymentControlContext)2 DefaultControlInitiated (org.killbill.billing.payment.core.sm.control.DefaultControlInitiated)2 PaymentStateControlContext (org.killbill.billing.payment.core.sm.control.PaymentStateControlContext)2 PaymentOperation (org.killbill.billing.payment.core.sm.payments.PaymentOperation)2 PluginDispatcherReturnType (org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType)2 ImmutableList (com.google.common.collect.ImmutableList)1 List (java.util.List)1