killbill-aplcache

Fixes #352

8/3/2015 9:22:36 PM

Details

diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/OperationControlCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/OperationControlCallback.java
index 34e2fd8..d5855d0 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/OperationControlCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/OperationControlCallback.java
@@ -56,6 +56,8 @@ import org.killbill.commons.locker.LockFailedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.MoreObjects;
+
 public abstract class OperationControlCallback extends OperationCallbackBase<Payment, PaymentApiException> implements OperationCallback {
 
     protected final PaymentProcessor paymentProcessor;
@@ -151,30 +153,26 @@ public abstract class OperationControlCallback extends OperationCallbackBase<Pay
     }
 
     @Override
-    protected OperationException rewrapExecutionException(final PaymentStateContext paymentStateContext, final ExecutionException e) {
-        if (e.getCause() instanceof OperationException) {
-            return (OperationException) e.getCause();
-        } else if (e.getCause() instanceof LockFailedException) {
+    protected OperationException unwrapExceptionFromDispatchedTask(final PaymentStateContext paymentStateContext, final Exception e) {
+
+        // If this is an ExecutionException we attempt to extract the cause first
+        final Throwable originalExceptionOrCause = e instanceof ExecutionException ? MoreObjects.firstNonNull(e.getCause(), e) : e;
+
+        if (originalExceptionOrCause instanceof OperationException) {
+            return (OperationException) originalExceptionOrCause;
+        } else if (originalExceptionOrCause instanceof LockFailedException) {
             final String format = String.format("Failed to lock account %s", paymentStateContext.getAccount().getExternalKey());
             logger.error(String.format(format));
-            return new OperationException(e, getOperationResultOnException(paymentStateContext));
+        } else if (originalExceptionOrCause instanceof TimeoutException) {
+            logger.warn("RetryOperationCallback call TIMEOUT for account {}", paymentStateContext.getAccount().getExternalKey());
+        } else if (originalExceptionOrCause instanceof InterruptedException) {
+            logger.error("RetryOperationCallback call was interrupted for account {}", paymentStateContext.getAccount().getExternalKey());
         } else /* most probably RuntimeException */ {
             logger.warn("RetryOperationCallback failed for account {}", paymentStateContext.getAccount().getExternalKey(), e);
-            return new OperationException(e, getOperationResultOnException(paymentStateContext));
         }
-    }
-
-    @Override
-    protected OperationException wrapTimeoutException(final PaymentStateContext paymentStateContext, final TimeoutException e) {
-        logger.warn("RetryOperationCallback call TIMEOUT for account {}", paymentStateContext.getAccount().getExternalKey());
         return new OperationException(e, getOperationResultOnException(paymentStateContext));
     }
 
-    @Override
-    protected OperationException wrapInterruptedException(final PaymentStateContext paymentStateContext, final InterruptedException e) {
-        logger.error("RetryOperationCallback call was interrupted for account {}", paymentStateContext.getAccount().getExternalKey());
-        return new OperationException(e, getOperationResultOnException(paymentStateContext));
-    }
 
     protected void executePluginOnSuccessCalls(final List<String> paymentControlPluginNames, final PaymentRoutingContext paymentControlContext) {
         for (final String pluginName : paymentControlPluginNames) {
@@ -253,10 +251,8 @@ public abstract class OperationControlCallback extends OperationCallbackBase<Pay
         final DateTime retryDate = executePluginOnFailureCalls(paymentStateControlContext.getPaymentControlPluginNames(), paymentControlContext);
         if (retryDate != null) {
             ((PaymentStateControlContext) paymentStateContext).setRetryDate(retryDate);
-            return OperationResult.FAILURE;
-        } else {
-            return OperationResult.EXCEPTION;
         }
+        return getOperationResultOnException(paymentStateContext);
     }
 
     private DateTime executePluginOnFailureCalls(final List<String> paymentControlPluginNames, final PaymentRoutingContext paymentControlContext) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/OperationCallbackBase.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/OperationCallbackBase.java
index 6a81f1d..8ab58ff 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/OperationCallbackBase.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/OperationCallbackBase.java
@@ -66,12 +66,12 @@ public abstract class OperationCallbackBase<CallbackOperationResult, CallbackOpe
             logger.debug("Successful plugin call for account {} with result {}", account.getExternalKey(), operationResult);
             return operationResult;
         } catch (final ExecutionException e) {
-            throw rewrapExecutionException(paymentStateContext, e);
+            throw unwrapExceptionFromDispatchedTask(paymentStateContext, e);
         } catch (final TimeoutException e) {
-            throw wrapTimeoutException(paymentStateContext, e);
+            throw unwrapExceptionFromDispatchedTask(paymentStateContext, e);
         } catch (final InterruptedException e) {
             Thread.currentThread().interrupt();
-            throw wrapInterruptedException(paymentStateContext, e);
+            throw unwrapExceptionFromDispatchedTask(paymentStateContext, e);
         }
     }
 
@@ -83,12 +83,5 @@ public abstract class OperationCallbackBase<CallbackOperationResult, CallbackOpe
     //
     protected abstract CallbackOperationResult doCallSpecificOperationCallback() throws CallbackOperationException;
 
-    //
-    // The methods below allow to convert the exceptions thrown back by the Executor into an appropriate  OperationException
-    //
-    protected abstract OperationException rewrapExecutionException(final PaymentStateContext paymentStateContext, final ExecutionException e);
-
-    protected abstract OperationException wrapTimeoutException(final PaymentStateContext paymentStateContext, final TimeoutException e);
-
-    protected abstract OperationException wrapInterruptedException(final PaymentStateContext paymentStateContext, final InterruptedException e);
+    protected abstract OperationException unwrapExceptionFromDispatchedTask(final PaymentStateContext paymentStateContext, final Exception e);
 }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/payments/PaymentOperation.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/payments/PaymentOperation.java
index 6d57033..ba6e48d 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/payments/PaymentOperation.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/payments/PaymentOperation.java
@@ -85,24 +85,26 @@ public abstract class PaymentOperation extends OperationCallbackBase<PaymentTran
     }
 
     @Override
-    protected OperationException rewrapExecutionException(final PaymentStateContext paymentStateContext, final ExecutionException e) {
+    protected OperationException unwrapExceptionFromDispatchedTask(final PaymentStateContext paymentStateContext, final Exception e) {
+
+        // If this is an ExecutionException we attempt to extract the cause first
+        final Throwable originalExceptionOrCause = e instanceof ExecutionException ? MoreObjects.firstNonNull(e.getCause(), e) : e;
+
         //
         // Any case of exception (checked or runtime) should lead to a TransactionStatus.UNKNOWN (and a XXX_ERRORED payment state).
         // In order to reach that state we create PaymentTransactionInfoPlugin with an PaymentPluginStatus.UNDEFINED status (and an OperationResult.EXCEPTION).
         //
-        final Throwable originalExceptionOrCause = MoreObjects.firstNonNull(e.getCause(), e);
         if (originalExceptionOrCause instanceof LockFailedException) {
             logger.warn("Failed to lock account {}", paymentStateContext.getAccount().getExternalKey());
+        } else if (originalExceptionOrCause instanceof TimeoutException) {
+            logger.error("Plugin call TIMEOUT for account {}", paymentStateContext.getAccount().getExternalKey());
+        } else if (originalExceptionOrCause instanceof InterruptedException) {
+            logger.error("Plugin call was interrupted for account {}", paymentStateContext.getAccount().getExternalKey());
         } else {
             logger.warn("Payment plugin call threw an exception for account {}", paymentStateContext.getAccount().getExternalKey(), originalExceptionOrCause);
         }
         return convertToUnknownTransactionStatusAndErroredPaymentState(originalExceptionOrCause);
-    }
 
-    @Override
-    protected OperationException wrapTimeoutException(final PaymentStateContext paymentStateContext, final TimeoutException e) {
-        logger.error("Plugin call TIMEOUT for account {}", paymentStateContext.getAccount().getExternalKey());
-        return convertToUnknownTransactionStatusAndErroredPaymentState(e);
     }
 
     //
@@ -122,16 +124,10 @@ public abstract class PaymentOperation extends OperationCallbackBase<PaymentTran
                                                                                                 paymentStateContext.getCallContext().getCreatedDate(),
                                                                                                 PaymentPluginStatus.UNDEFINED,
                                                                                                 null);
-
         paymentStateContext.setPaymentTransactionInfoPlugin(paymentInfoPlugin);
         return new OperationException(e, OperationResult.EXCEPTION);
     }
 
-    @Override
-    protected OperationException wrapInterruptedException(final PaymentStateContext paymentStateContext, final InterruptedException e) {
-        logger.error("Plugin call was interrupted for account {}", paymentStateContext.getAccount().getExternalKey());
-        return new OperationException(e, OperationResult.EXCEPTION);
-    }
 
     @Override
     protected abstract PaymentTransactionInfoPlugin doCallSpecificOperationCallback() throws PaymentPluginApiException;