killbill-memoizeit
Changes
payment/src/main/java/org/killbill/billing/payment/core/PluginRoutingPaymentProcessor.java 222(+109 -113)
payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentEnteringStateCallback.java 2(+1 -1)
payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentLeavingStateCallback.java 2(+1 -1)
payment/src/main/java/org/killbill/billing/payment/core/sm/PluginRoutingPaymentAutomatonRunner.java 24(+9 -15)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java 20(+10 -10)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryLeavingStateCallback.java 41(+23 -18)
pom.xml 2(+1 -1)
Details
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index ce1496b..e66f187 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -83,6 +83,7 @@ import org.killbill.billing.payment.api.Payment;
import org.killbill.billing.payment.api.PaymentApi;
import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PaymentMethod;
+import org.killbill.billing.payment.api.PaymentOptions;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.util.api.AuditLevel;
@@ -710,6 +711,7 @@ public class AccountResource extends JaxRsResourceBase {
public Response processPayment(final PaymentTransactionJson json,
@PathParam("accountId") final String accountIdStr,
@QueryParam("paymentMethodId") final String paymentMethodIdStr,
+ @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
@QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@@ -729,22 +731,23 @@ public class AccountResource extends JaxRsResourceBase {
final UUID paymentId = json.getPaymentId() == null ? null : UUID.fromString(json.getPaymentId());
final TransactionType transactionType = TransactionType.valueOf(json.getTransactionType());
+ final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
final Payment result;
switch (transactionType) {
case AUTHORIZE:
- result = paymentApi.createAuthorization(account, paymentMethodId, paymentId, json.getAmount(), currency,
- json.getPaymentExternalKey(), json.getTransactionExternalKey(),
- pluginProperties, callContext);
+ result = paymentApi.createAuthorizationWithPaymentControl(account, paymentMethodId, paymentId, json.getAmount(), currency,
+ json.getPaymentExternalKey(), json.getTransactionExternalKey(),
+ pluginProperties, paymentOptions, callContext);
break;
case PURCHASE:
- result = paymentApi.createPurchase(account, paymentMethodId, paymentId, json.getAmount(), currency,
- json.getPaymentExternalKey(), json.getTransactionExternalKey(),
- pluginProperties, callContext);
+ result = paymentApi.createPurchaseWithPaymentControl(account, paymentMethodId, paymentId, json.getAmount(), currency,
+ json.getPaymentExternalKey(), json.getTransactionExternalKey(),
+ pluginProperties, paymentOptions, callContext);
break;
case CREDIT:
- result = paymentApi.createCredit(account, paymentMethodId, paymentId, json.getAmount(), currency,
- json.getPaymentExternalKey(), json.getTransactionExternalKey(),
- pluginProperties, callContext);
+ result = paymentApi.createCreditWithPaymentControl(account, paymentMethodId, paymentId, json.getAmount(), currency,
+ json.getPaymentExternalKey(), json.getTransactionExternalKey(),
+ pluginProperties, paymentOptions, callContext);
break;
default:
return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + transactionType + " is not allowed for an account").build();
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index d7c5ab8..836d8c5 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -83,6 +83,7 @@ public interface JaxrsResource {
public static final String QUERY_PAYMENT_AMOUNT = "paymentAmount";
public static final String QUERY_PAYMENT_WITH_REFUNDS_AND_CHARGEBACKS = "withRefundsAndChargebacks";
public static final String QUERY_PAYMENT_PLUGIN_NAME = "pluginName";
+ public static final String QUERY_PAYMENT_CONTROL_PLUGIN_NAME = "controlPluginName";
public static final String QUERY_TAGS = "tagList";
public static final String QUERY_TAGS_INCLUDED_DELETED = "includedDeleted";
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
index 7d88bef..76ab053 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -372,6 +372,14 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
}
protected PaymentOptions createInvoicePaymentControlPluginApiPaymentOptions(final boolean isExternalPayment) {
+ return createControlPluginApiPaymentOptions(isExternalPayment, ImmutableList.<String>of("__INVOICE_PAYMENT_CONTROL_PLUGIN__"));
+ }
+
+ protected PaymentOptions createControlPluginApiPaymentOptions(@Nullable final List<String> paymentControlPluginNames) {
+ return createControlPluginApiPaymentOptions(false, paymentControlPluginNames);
+ }
+
+ protected PaymentOptions createControlPluginApiPaymentOptions(final boolean isExternalPayment, final List<String> paymentControlPluginNames) {
return new PaymentOptions() {
@Override
public boolean isExternalPayment() {
@@ -380,8 +388,8 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
@Override
public List<String> getPaymentControlPluginNames() {
- /* Will default to org.killbill.payment.invoice.plugin in payment sub-system */
- return null;
+ // DefaultPaymentApi will add the default configured ones to this list
+ return paymentControlPluginNames;
}
};
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
index 2bf74bb..2bb3816 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
@@ -32,6 +32,7 @@ import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.payment.core.PaymentMethodProcessor;
import org.killbill.billing.payment.core.PaymentProcessor;
import org.killbill.billing.payment.core.PluginRoutingPaymentProcessor;
+import org.killbill.billing.payment.invoice.InvoicePaymentRoutingPluginApi;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.callcontext.TenantContext;
@@ -40,6 +41,8 @@ import org.killbill.billing.util.entity.Pagination;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.collect.ImmutableList;
+
public class DefaultPaymentApi implements PaymentApi {
private static final boolean SHOULD_LOCK_ACCOUNT = true;
@@ -66,7 +69,6 @@ public class DefaultPaymentApi implements PaymentApi {
@Override
public Payment createAuthorization(final Account account, final UUID paymentMethodId, @Nullable final UUID paymentId, final BigDecimal amount, final Currency currency, @Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
-
checkNotNullParameter(account, "account");
checkNotNullParameter(paymentMethodId, "paymentMethodId");
checkNotNullParameter(amount, "amount");
@@ -82,6 +84,29 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
+ public Payment createAuthorizationWithPaymentControl(final Account account, final UUID paymentMethodId, final UUID paymentId, final BigDecimal amount, final Currency currency,
+ @Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey,
+ final Iterable<PluginProperty> properties, final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
+ final List<String> paymentControlPluginNames = toPaymentControlPluginNames(paymentOptions);
+ if (paymentControlPluginNames.isEmpty()) {
+ return createAuthorization(account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey, properties, callContext);
+ }
+
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(paymentMethodId, "paymentMethodId");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(properties, "plugin properties");
+ checkPositiveAmount(amount);
+
+ logAPICall(TransactionType.AUTHORIZE.name(), account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey);
+
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ return pluginRoutingPaymentProcessor.createAuthorization(IS_API_PAYMENT, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
+ properties, paymentControlPluginNames, callContext, internalCallContext);
+ }
+
+ @Override
public Payment createCapture(final Account account, final UUID paymentId, final BigDecimal amount, final Currency currency, @Nullable final String paymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
@@ -101,7 +126,6 @@ public class DefaultPaymentApi implements PaymentApi {
@Override
public Payment createPurchase(final Account account, final UUID paymentMethodId, @Nullable final UUID paymentId, final BigDecimal amount, final Currency currency, @Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
-
checkNotNullParameter(account, "account");
checkNotNullParameter(paymentMethodId, "paymentMethodId");
checkNotNullParameter(amount, "amount");
@@ -119,6 +143,10 @@ public class DefaultPaymentApi implements PaymentApi {
@Override
public Payment createPurchaseWithPaymentControl(final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID paymentId, final BigDecimal amount, final Currency currency, final String paymentExternalKey, final String paymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
+ final List<String> paymentControlPluginNames = toPaymentControlPluginNames(paymentOptions);
+ if (paymentControlPluginNames.isEmpty()) {
+ return createPurchase(account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey, properties, callContext);
+ }
checkNotNullParameter(account, "account");
checkNotNullParameter(amount, "amount");
@@ -140,7 +168,7 @@ public class DefaultPaymentApi implements PaymentApi {
paymentMethodId :
paymentMethodProcessor.createOrGetExternalPaymentMethod(UUID.randomUUID().toString(), account, properties, callContext, internalCallContext);
return pluginRoutingPaymentProcessor.createPurchase(IS_API_PAYMENT, account, nonNulPaymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
- properties, toPaymentControlPluginNames(paymentOptions), callContext, internalCallContext);
+ properties, paymentControlPluginNames, callContext, internalCallContext);
}
@@ -181,6 +209,10 @@ public class DefaultPaymentApi implements PaymentApi {
@Override
public Payment createRefundWithPaymentControl(final Account account, final UUID paymentId, @Nullable final BigDecimal amount, final Currency currency, final String paymentTransactionExternalKey, final Iterable<PluginProperty> properties,
final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
+ final List<String> paymentControlPluginNames = toPaymentControlPluginNames(paymentOptions);
+ if (paymentControlPluginNames.isEmpty()) {
+ return createRefund(account, paymentId, amount, currency, paymentTransactionExternalKey, properties, callContext);
+ }
checkNotNullParameter(account, "account");
checkNotNullParameter(currency, "currency");
@@ -195,7 +227,7 @@ public class DefaultPaymentApi implements PaymentApi {
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
return pluginRoutingPaymentProcessor.createRefund(IS_API_PAYMENT, account, paymentId, amount, currency, paymentTransactionExternalKey,
- properties, toPaymentControlPluginNames(paymentOptions), callContext, internalCallContext);
+ properties, paymentControlPluginNames, callContext, internalCallContext);
}
@@ -203,7 +235,6 @@ public class DefaultPaymentApi implements PaymentApi {
public Payment createCredit(final Account account, final UUID paymentMethodId, @Nullable final UUID paymentId, final BigDecimal amount, final Currency currency,
@Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
-
checkNotNullParameter(account, "account");
checkNotNullParameter(paymentMethodId, "paymentMethodId");
checkNotNullParameter(amount, "amount");
@@ -220,8 +251,30 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public Payment notifyPendingTransactionOfStateChanged(final Account account, final UUID paymentTransactionId, final boolean isSuccess, final CallContext callContext) throws PaymentApiException {
+ public Payment createCreditWithPaymentControl(final Account account, final UUID paymentMethodId, @Nullable final UUID paymentId, final BigDecimal amount, final Currency currency,
+ @Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey,
+ final Iterable<PluginProperty> properties, final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
+ final List<String> paymentControlPluginNames = toPaymentControlPluginNames(paymentOptions);
+ if (paymentControlPluginNames.isEmpty()) {
+ return createCredit(account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey, properties, callContext);
+ }
+
+ checkNotNullParameter(account, "account");
+ checkNotNullParameter(paymentMethodId, "paymentMethodId");
+ checkNotNullParameter(amount, "amount");
+ checkNotNullParameter(currency, "currency");
+ checkNotNullParameter(properties, "plugin properties");
+ checkPositiveAmount(amount);
+ logAPICall(TransactionType.CREDIT.name(), account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey);
+
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ return pluginRoutingPaymentProcessor.createCredit(IS_API_PAYMENT, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
+ properties, paymentControlPluginNames, callContext, internalCallContext);
+ }
+
+ @Override
+ public Payment notifyPendingTransactionOfStateChanged(final Account account, final UUID paymentTransactionId, final boolean isSuccess, final CallContext callContext) throws PaymentApiException {
checkNotNullParameter(account, "account");
checkNotNullParameter(paymentTransactionId, "paymentTransactionId");
@@ -254,6 +307,11 @@ public class DefaultPaymentApi implements PaymentApi {
@Override
public Payment createChargebackWithPaymentControl(final Account account, final UUID paymentId, final BigDecimal amount, final Currency currency, final String paymentTransactionExternalKey, final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
+ final List<String> paymentControlPluginNames = toPaymentControlPluginNames(paymentOptions);
+ if (paymentControlPluginNames.isEmpty()) {
+ return createChargeback(account, paymentId, amount, currency, paymentTransactionExternalKey, callContext);
+ }
+
checkNotNullParameter(account, "account");
checkNotNullParameter(amount, "amount");
checkNotNullParameter(currency, "currency");
@@ -262,7 +320,7 @@ public class DefaultPaymentApi implements PaymentApi {
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
return pluginRoutingPaymentProcessor.createChargeback(account, paymentId, paymentTransactionExternalKey, amount, currency,
- toPaymentControlPluginNames(paymentOptions), callContext, internalCallContext);
+ paymentControlPluginNames, callContext, internalCallContext);
}
@Override
@@ -427,7 +485,21 @@ public class DefaultPaymentApi implements PaymentApi {
}
private List<String> toPaymentControlPluginNames(final PaymentOptions paymentOptions) {
- return paymentOptions.getPaymentControlPluginNames() != null ? paymentOptions.getPaymentControlPluginNames() : paymentConfig.getPaymentControlPluginNames();
+ // Special path for JAX-RS InvoicePayment endpoints (see JaxRsResourceBase)
+ if (paymentConfig.getPaymentControlPluginNames() != null &&
+ paymentOptions.getPaymentControlPluginNames() != null &&
+ paymentOptions.getPaymentControlPluginNames().size() == 1 &&
+ InvoicePaymentRoutingPluginApi.PLUGIN_NAME.equals(paymentOptions.getPaymentControlPluginNames().get(0))) {
+ final List<String> paymentControlPluginNames = new LinkedList<String>(paymentOptions.getPaymentControlPluginNames());
+ paymentControlPluginNames.addAll(paymentConfig.getPaymentControlPluginNames());
+ return paymentControlPluginNames;
+ } else if (paymentOptions.getPaymentControlPluginNames() != null && !paymentOptions.getPaymentControlPluginNames().isEmpty()) {
+ return paymentOptions.getPaymentControlPluginNames();
+ } else if (paymentConfig.getPaymentControlPluginNames() != null && !paymentConfig.getPaymentControlPluginNames().isEmpty()) {
+ return paymentConfig.getPaymentControlPluginNames();
+ } else {
+ return ImmutableList.<String>of();
+ }
}
private void checkNotNullParameter(final Object parameter, final String parameterName) throws PaymentApiException {
diff --git a/payment/src/main/java/org/killbill/billing/payment/bus/InvoiceHandler.java b/payment/src/main/java/org/killbill/billing/payment/bus/InvoiceHandler.java
index a904698..80c1770 100644
--- a/payment/src/main/java/org/killbill/billing/payment/bus/InvoiceHandler.java
+++ b/payment/src/main/java/org/killbill/billing/payment/bus/InvoiceHandler.java
@@ -20,6 +20,7 @@ package org.killbill.billing.payment.bus;
import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@@ -32,8 +33,8 @@ import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.events.InvoiceCreationInternalEvent;
import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PluginProperty;
-import org.killbill.billing.payment.invoice.InvoicePaymentRoutingPluginApi;
import org.killbill.billing.payment.core.PluginRoutingPaymentProcessor;
+import org.killbill.billing.payment.invoice.InvoicePaymentRoutingPluginApi;
import org.killbill.billing.util.cache.Cachable.CacheType;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.callcontext.CallContext;
@@ -45,7 +46,6 @@ import org.killbill.billing.util.dao.NonEntityDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.collect.ImmutableList;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
@@ -93,9 +93,10 @@ public class InvoiceHandler {
final CallContext callContext = internalContext.toCallContext(nonEntityDao.retrieveIdFromObject(internalContext.getTenantRecordId(), ObjectType.TENANT, controllerDispatcher.getCacheController(CacheType.OBJECT_ID)));
final BigDecimal amountToBePaid = null; // We let the plugin compute how much should be paid
- final List<String> paymentControlPluginNames = paymentConfig.getPaymentControlPluginNames() != null ? paymentConfig.getPaymentControlPluginNames() : ImmutableList.of(InvoicePaymentRoutingPluginApi.PLUGIN_NAME);
+ final List<String> paymentControlPluginNames = paymentConfig.getPaymentControlPluginNames() != null ? new LinkedList<String>(paymentConfig.getPaymentControlPluginNames()) : new LinkedList<String>();
+ paymentControlPluginNames.add(InvoicePaymentRoutingPluginApi.PLUGIN_NAME);
pluginRoutingPaymentProcessor.createPurchase(false, account, account.getPaymentMethodId(), null, amountToBePaid, account.getCurrency(), UUID.randomUUID().toString(), UUID.randomUUID().toString(),
- properties, paymentControlPluginNames, callContext, internalContext);
+ properties, paymentControlPluginNames, callContext, internalContext);
} catch (final AccountApiException e) {
log.error("Failed to process invoice payment", e);
} catch (final PaymentApiException e) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PluginRoutingPaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PluginRoutingPaymentProcessor.java
index a1c4e75..79be2f0 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PluginRoutingPaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PluginRoutingPaymentProcessor.java
@@ -17,6 +17,7 @@
package org.killbill.billing.payment.core;
import java.math.BigDecimal;
+import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
@@ -88,124 +89,123 @@ public class PluginRoutingPaymentProcessor extends ProcessorBase {
}
public Payment createAuthorization(final boolean isApiPayment, final Account account, final UUID paymentMethodId, @Nullable final UUID paymentId, final BigDecimal amount, final Currency currency, final String paymentExternalKey, final String transactionExternalKey,
- final Iterable<PluginProperty> properties, final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final Iterable<PluginProperty> properties, final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return pluginControlledPaymentAutomatonRunner.run(isApiPayment,
- TransactionType.AUTHORIZE,
- account,
- paymentMethodId,
- paymentId,
- paymentExternalKey,
- transactionExternalKey,
- amount,
- currency,
- properties,
- paymentControlPluginNames,
- callContext, internalCallContext);
+ TransactionType.AUTHORIZE,
+ account,
+ paymentMethodId,
+ paymentId,
+ paymentExternalKey,
+ transactionExternalKey,
+ amount,
+ currency,
+ properties,
+ paymentControlPluginNames,
+ callContext, internalCallContext);
}
public Payment createCapture(final boolean isApiPayment, final Account account, final UUID paymentId, final BigDecimal amount, final Currency currency,
- final String transactionExternalKey,
- final Iterable<PluginProperty> properties, final List<String> paymentControlPluginNames,
- final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final String transactionExternalKey,
+ final Iterable<PluginProperty> properties, final List<String> paymentControlPluginNames,
+ final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return pluginControlledPaymentAutomatonRunner.run(isApiPayment,
- TransactionType.CAPTURE,
- account,
- null,
- paymentId,
- null,
- transactionExternalKey,
- amount,
- currency,
- properties,
- paymentControlPluginNames,
- callContext, internalCallContext);
+ TransactionType.CAPTURE,
+ account,
+ null,
+ paymentId,
+ null,
+ transactionExternalKey,
+ amount,
+ currency,
+ properties,
+ paymentControlPluginNames,
+ callContext, internalCallContext);
}
public Payment createPurchase(final boolean isApiPayment, final Account account, final UUID paymentMethodId, final UUID paymentId, final BigDecimal amount, final Currency currency,
- final String paymentExternalKey, final String transactionExternalKey, final Iterable<PluginProperty> properties,
- final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final String paymentExternalKey, final String transactionExternalKey, final Iterable<PluginProperty> properties,
+ final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return pluginControlledPaymentAutomatonRunner.run(isApiPayment,
- TransactionType.PURCHASE,
- account,
- paymentMethodId,
- paymentId,
- paymentExternalKey,
- transactionExternalKey,
- amount,
- currency,
- properties,
- paymentControlPluginNames,
- callContext, internalCallContext);
+ TransactionType.PURCHASE,
+ account,
+ paymentMethodId,
+ paymentId,
+ paymentExternalKey,
+ transactionExternalKey,
+ amount,
+ currency,
+ properties,
+ paymentControlPluginNames,
+ callContext, internalCallContext);
}
public Payment createVoid(final boolean isApiPayment, final Account account, final UUID paymentId, final String transactionExternalKey,
- final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return pluginControlledPaymentAutomatonRunner.run(isApiPayment,
- TransactionType.VOID,
- account,
- null,
- paymentId,
- null,
- transactionExternalKey,
- null,
- null,
- properties,
- null,
- callContext, internalCallContext);
+ TransactionType.VOID,
+ account,
+ null,
+ paymentId,
+ null,
+ transactionExternalKey,
+ null,
+ null,
+ properties,
+ null,
+ callContext, internalCallContext);
}
public Payment createRefund(final boolean isApiPayment, final Account account, final UUID paymentId, final BigDecimal amount, final Currency currency, final String transactionExternalKey,
- final Iterable<PluginProperty> properties, final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final Iterable<PluginProperty> properties, final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return pluginControlledPaymentAutomatonRunner.run(isApiPayment,
- TransactionType.REFUND,
- account,
- null,
- paymentId,
- null,
- transactionExternalKey,
- amount,
- currency,
- properties,
- paymentControlPluginNames,
- callContext, internalCallContext);
+ TransactionType.REFUND,
+ account,
+ null,
+ paymentId,
+ null,
+ transactionExternalKey,
+ amount,
+ currency,
+ properties,
+ paymentControlPluginNames,
+ callContext, internalCallContext);
}
public Payment createCredit(final boolean isApiPayment, final Account account, final UUID paymentMethodId, final UUID paymentId, final BigDecimal amount, final Currency currency, final String paymentExternalKey,
- final String transactionExternalKey, final Iterable<PluginProperty> properties, final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final String transactionExternalKey, final Iterable<PluginProperty> properties, final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return pluginControlledPaymentAutomatonRunner.run(isApiPayment,
- TransactionType.CREDIT,
- account,
- paymentMethodId,
- paymentId,
- paymentExternalKey,
- transactionExternalKey,
- amount,
- currency,
- properties,
- paymentControlPluginNames,
- callContext, internalCallContext);
+ TransactionType.CREDIT,
+ account,
+ paymentMethodId,
+ paymentId,
+ paymentExternalKey,
+ transactionExternalKey,
+ amount,
+ currency,
+ properties,
+ paymentControlPluginNames,
+ callContext, internalCallContext);
}
public Payment createChargeback(final Account account, final UUID paymentId, final String transactionExternalKey, final BigDecimal amount, final Currency currency,
- final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
+ final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return pluginControlledPaymentAutomatonRunner.run(true,
- TransactionType.CHARGEBACK,
- account,
- null,
- paymentId,
- null,
- transactionExternalKey,
- amount,
- currency,
- ImmutableList.<PluginProperty>of(),
- paymentControlPluginNames,
- callContext, internalCallContext);
+ TransactionType.CHARGEBACK,
+ account,
+ null,
+ paymentId,
+ null,
+ transactionExternalKey,
+ amount,
+ currency,
+ ImmutableList.<PluginProperty>of(),
+ paymentControlPluginNames,
+ callContext, internalCallContext);
}
public void retryPaymentTransaction(final UUID attemptId, final List<String> paymentControlPluginNames, final InternalCallContext internalCallContext) {
try {
-
final PaymentAttemptModelDao attempt = paymentDao.getPaymentAttempt(attemptId, internalCallContext);
final PaymentModelDao payment = paymentDao.getPaymentByExternalKey(attempt.getPaymentExternalKey(), internalCallContext);
final UUID paymentId = payment != null ? payment.getId() : null;
@@ -217,39 +217,35 @@ public class PluginRoutingPaymentProcessor extends ProcessorBase {
final State state = retrySMHelper.getState(attempt.getStateName());
pluginControlledPaymentAutomatonRunner.run(state,
- false,
- attempt.getTransactionType(),
- account,
- attempt.getPaymentMethodId(),
- paymentId,
- attempt.getPaymentExternalKey(),
- attempt.getTransactionExternalKey(),
- attempt.getAmount(),
- attempt.getCurrency(),
- pluginProperties,
- paymentControlPluginNames,
- callContext,
- internalCallContext);
-
- } catch (AccountApiException e) {
+ false,
+ attempt.getTransactionType(),
+ account,
+ attempt.getPaymentMethodId(),
+ paymentId,
+ attempt.getPaymentExternalKey(),
+ attempt.getTransactionExternalKey(),
+ attempt.getAmount(),
+ attempt.getCurrency(),
+ pluginProperties,
+ paymentControlPluginNames,
+ callContext,
+ internalCallContext);
+
+ } catch (final AccountApiException e) {
log.warn("Failed to retry attempt " + attemptId + toPluginNamesOnError(" for plugins ", paymentControlPluginNames), e);
- } catch (PaymentApiException e) {
+ } catch (final PaymentApiException e) {
log.warn("Failed to retry attempt " + attemptId + toPluginNamesOnError(" for plugins ", paymentControlPluginNames), e);
- } catch (PluginPropertySerializerException e) {
+ } catch (final PluginPropertySerializerException e) {
log.warn("Failed to retry attempt " + attemptId + toPluginNamesOnError(" for plugins ", paymentControlPluginNames), e);
- } catch (MissingEntryException e) {
+ } catch (final MissingEntryException e) {
log.warn("Failed to retry attempt " + attemptId + toPluginNamesOnError(" for plugins ", paymentControlPluginNames), e);
}
}
- private String toPluginNamesOnError(final String prefixMessage, final List<String> paymentControlPluginNames) {
- if (paymentControlPluginNames == null || paymentControlPluginNames.size() == 0) {
+ private String toPluginNamesOnError(final String prefixMessage, final Collection<String> paymentControlPluginNames) {
+ if (paymentControlPluginNames == null || paymentControlPluginNames.isEmpty()) {
return "";
}
- final StringBuilder tmp = new StringBuilder(prefixMessage)
- .append("(")
- .append(JOINER.join(paymentControlPluginNames))
- .append(")");
- return tmp.toString();
+ return prefixMessage + "(" + JOINER.join(paymentControlPluginNames) + ")";
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackOperation.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackOperation.java
index 04afc77..d328dd3 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackOperation.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/ChargebackOperation.java
@@ -68,13 +68,13 @@ public class ChargebackOperation extends PaymentOperation {
status = PaymentPluginStatus.PROCESSED;
}
return new DefaultNoOpPaymentInfoPlugin(paymentStateContext.getPaymentId(),
- paymentStateContext.getTransactionId(),
- TransactionType.CHARGEBACK,
- paymentStateContext.getAmount(),
- paymentStateContext.getCurrency(),
- null,
- null,
- status,
- null);
+ paymentStateContext.getTransactionId(),
+ TransactionType.CHARGEBACK,
+ paymentStateContext.getAmount(),
+ paymentStateContext.getCurrency(),
+ null,
+ null,
+ status,
+ null);
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java
index 55fcb3f..4f72dae 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java
@@ -25,17 +25,11 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.killbill.billing.ErrorCode;
-import org.killbill.billing.account.api.Account;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.api.Currency;
-import org.killbill.billing.events.BusInternalEvent;
import org.killbill.billing.osgi.api.OSGIServiceRegistration;
-import org.killbill.billing.payment.api.DefaultPaymentErrorEvent;
-import org.killbill.billing.payment.api.DefaultPaymentInfoEvent;
-import org.killbill.billing.payment.api.DefaultPaymentPluginErrorEvent;
import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.TransactionStatus;
-import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.dao.PaymentDao;
import org.killbill.billing.payment.dao.PaymentMethodModelDao;
import org.killbill.billing.payment.dao.PaymentModelDao;
@@ -43,11 +37,9 @@ import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin;
import org.killbill.bus.api.PersistentBus;
-import org.killbill.bus.api.PersistentBus.EventBusException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
public class PaymentAutomatonDAOHelper {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java
index 7d79cfb..aed47f5 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java
@@ -45,11 +45,11 @@ import org.killbill.billing.osgi.api.OSGIServiceRegistration;
import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionType;
-import org.killbill.billing.payment.invoice.InvoicePaymentRoutingPluginApi;
import org.killbill.billing.payment.dao.PaymentDao;
import org.killbill.billing.payment.dao.PaymentModelDao;
import org.killbill.billing.payment.dispatcher.PluginDispatcher;
import org.killbill.billing.payment.glue.PaymentModule;
+import org.killbill.billing.payment.invoice.InvoicePaymentRoutingPluginApi;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.config.PaymentConfig;
@@ -102,7 +102,6 @@ public class PaymentAutomatonRunner {
@Nullable final BigDecimal amount, @Nullable final Currency currency,
final boolean shouldLockAccount, final OperationResult overridePluginOperationResult, final Iterable<PluginProperty> properties,
final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
-
final DateTime utcNow = clock.getUTCNow();
final PaymentStateContext paymentStateContext = new PaymentStateContext(isApiPayment, paymentId, transactionId, attemptId, paymentExternalKey, paymentTransactionExternalKey, transactionType,
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentEnteringStateCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentEnteringStateCallback.java
index e31416e..f3a81f7 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentEnteringStateCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentEnteringStateCallback.java
@@ -82,7 +82,7 @@ public abstract class PaymentEnteringStateCallback implements EnteringStateCallb
// and decides to return null; in all cases this is seen as a PLUGIN_FAILURE
//
if (paymentInfoPlugin == null || paymentInfoPlugin.getStatus() == null) {
- return TransactionStatus.PLUGIN_FAILURE;
+ return TransactionStatus.PLUGIN_FAILURE;
}
//
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentLeavingStateCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentLeavingStateCallback.java
index 898669e..aa3a58b 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentLeavingStateCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentLeavingStateCallback.java
@@ -54,7 +54,7 @@ public abstract class PaymentLeavingStateCallback implements LeavingStateCallbac
if (paymentStateContext.getTransactionId() == null) {
daoHelper.createNewPaymentTransaction();
} else {
- final PaymentTransactionModelDao transactionModelDao = daoHelper.paymentDao.getPaymentTransaction(paymentStateContext.getTransactionId(), paymentStateContext.getInternalCallContext());
+ final PaymentTransactionModelDao transactionModelDao = daoHelper.paymentDao.getPaymentTransaction(paymentStateContext.getTransactionId(), paymentStateContext.getInternalCallContext());
paymentStateContext.setPaymentTransactionModelDao(transactionModelDao);
}
} catch (PaymentApiException e) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentOperation.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentOperation.java
index daf9c67..bc9bfdb 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentOperation.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentOperation.java
@@ -205,7 +205,7 @@ public abstract class PaymentOperation extends OperationCallbackBase<PaymentTran
}
private OperationResult processPaymentInfoPlugin() {
- if (paymentStateContext.getPaymentInfoPlugin() == null) {
+ if (paymentStateContext.getPaymentInfoPlugin() == null || paymentStateContext.getPaymentInfoPlugin().getStatus() == null) {
return OperationResult.FAILURE;
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateContext.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateContext.java
index 3aafe01..28af33a 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateContext.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateContext.java
@@ -47,12 +47,12 @@ public class PaymentStateContext {
protected PaymentTransactionInfoPlugin paymentInfoPlugin;
protected BigDecimal amount;
protected String paymentExternalKey;
+ protected String paymentTransactionExternalKey;
protected Currency currency;
// Can be updated later via paymentTransactionModelDao (e.g. for auth or purchase)
protected final UUID paymentId;
protected final UUID transactionId;
- protected final String paymentTransactionExternalKey;
protected final Account account;
protected final TransactionType transactionType;
protected final boolean shouldLockAccountAndDispatch;
@@ -80,7 +80,7 @@ public class PaymentStateContext {
this.isApiPayment = isApiPayment;
this.paymentId = paymentId;
this.transactionId = transactionId;
- this.attemptId= attemptId;
+ this.attemptId = attemptId;
this.paymentExternalKey = paymentExternalKey;
this.paymentTransactionExternalKey = paymentTransactionExternalKey;
this.transactionType = transactionType;
@@ -148,6 +148,10 @@ public class PaymentStateContext {
return paymentTransactionExternalKey;
}
+ public void setPaymentTransactionExternalKey(final String paymentTransactionExternalKey) {
+ this.paymentTransactionExternalKey = paymentTransactionExternalKey;
+ }
+
public Account getAccount() {
return account;
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateMachineHelper.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateMachineHelper.java
index bc58d65..dfea014 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateMachineHelper.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateMachineHelper.java
@@ -121,7 +121,6 @@ public class PaymentStateMachineHelper {
}
}
-
public String getErroredStateForTransaction(final TransactionType transactionType) {
switch (transactionType) {
case AUTHORIZE:
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginRoutingPaymentAutomatonRunner.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginRoutingPaymentAutomatonRunner.java
index 00e4435..1731335 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginRoutingPaymentAutomatonRunner.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PluginRoutingPaymentAutomatonRunner.java
@@ -71,7 +71,7 @@ public class PluginRoutingPaymentAutomatonRunner extends PaymentAutomatonRunner
@Inject
public PluginRoutingPaymentAutomatonRunner(@Named(PaymentModule.STATE_MACHINE_PAYMENT) final StateMachineConfig stateMachineConfig, final PaymentDao paymentDao, final GlobalLocker locker, final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
final OSGIServiceRegistration<PaymentRoutingPluginApi> retryPluginRegistry, final Clock clock, final PaymentProcessor paymentProcessor, @Named(RETRYABLE_NAMED) final RetryServiceScheduler retryServiceScheduler,
- final PaymentConfig paymentConfig, @com.google.inject.name.Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor, PaymentStateMachineHelper paymentSMHelper, RetryStateMachineHelper retrySMHelper, final PersistentBus eventBus) {
+ final PaymentConfig paymentConfig, @com.google.inject.name.Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor, final PaymentStateMachineHelper paymentSMHelper, final RetryStateMachineHelper retrySMHelper, final PersistentBus eventBus) {
super(stateMachineConfig, paymentConfig, paymentDao, locker, pluginRegistry, clock, executor, eventBus, paymentSMHelper);
this.paymentProcessor = paymentProcessor;
this.paymentControlPluginRegistry = retryPluginRegistry;
@@ -93,23 +93,20 @@ public class PluginRoutingPaymentAutomatonRunner extends PaymentAutomatonRunner
@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 RetryablePaymentStateContext paymentStateContext = createContext(isApiPayment, transactionType, account, paymentMethodId,
- paymentId, paymentExternalKey,
- paymentTransactionExternalKey,
- amount, currency,
- properties, paymentControlPluginNames, callContext, internalCallContext);
+ paymentId, paymentExternalKey,
+ paymentTransactionExternalKey,
+ amount, currency,
+ properties, paymentControlPluginNames, callContext, internalCallContext);
try {
-
final OperationCallback callback = createOperationCallback(transactionType, paymentStateContext);
final LeavingStateCallback leavingStateCallback = new RetryLeavingStateCallback(this, paymentStateContext, paymentDao, retrySMHelper.getInitialState(), retrySMHelper.getRetriedState(), transactionType);
final EnteringStateCallback enteringStateCallback = new RetryEnteringStateCallback(this, paymentStateContext, retryServiceScheduler);
state.runOperation(retrySMHelper.getRetryOperation(), callback, enteringStateCallback, leavingStateCallback);
-
- } catch (MissingEntryException e) {
+ } catch (final MissingEntryException e) {
throw new PaymentApiException(e.getCause(), ErrorCode.PAYMENT_INTERNAL_ERROR, Objects.firstNonNull(e.getMessage(), ""));
- } catch (OperationException e) {
+ } catch (final OperationException e) {
if (e.getCause() == null) {
// Unclear if we should check whether there is a result that was set and return that result.
throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, Objects.firstNonNull(e.getMessage(), ""));
@@ -123,18 +120,15 @@ public class PluginRoutingPaymentAutomatonRunner extends PaymentAutomatonRunner
}
public Payment completeRun(final RetryablePaymentStateContext paymentStateContext) throws PaymentApiException {
-
try {
-
final OperationCallback callback = new RetryCompletionOperationCallback(locker, paymentPluginDispatcher, paymentStateContext, paymentProcessor, paymentControlPluginRegistry);
final LeavingStateCallback leavingStateCallback = new RetryNoopLeavingStateCallback();
final EnteringStateCallback enteringStateCallback = new RetryEnteringStateCallback(this, paymentStateContext, retryServiceScheduler);
retrySMHelper.getInitialState().runOperation(retrySMHelper.getRetryOperation(), callback, enteringStateCallback, leavingStateCallback);
-
- } catch (MissingEntryException e) {
+ } catch (final MissingEntryException e) {
throw new PaymentApiException(e.getCause(), ErrorCode.PAYMENT_INTERNAL_ERROR, Objects.firstNonNull(e.getMessage(), ""));
- } catch (OperationException e) {
+ } catch (final OperationException e) {
if (e.getCause() == null) {
throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, Objects.firstNonNull(e.getMessage(), ""));
} else if (e.getCause() instanceof PaymentApiException) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PurchaseOperation.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PurchaseOperation.java
index 38757f5..446ca21 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PurchaseOperation.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PurchaseOperation.java
@@ -40,12 +40,12 @@ public class PurchaseOperation extends PaymentOperation {
protected PaymentTransactionInfoPlugin doCallSpecificOperationCallback() throws PaymentPluginApiException {
logger.debug("Starting PURCHASE for payment {} ({} {})", paymentStateContext.getPaymentId(), paymentStateContext.getAmount(), paymentStateContext.getCurrency());
return plugin.purchasePayment(paymentStateContext.getAccount().getId(),
- paymentStateContext.getPaymentId(),
- paymentStateContext.getTransactionId(),
- paymentStateContext.getPaymentMethodId(),
- paymentStateContext.getAmount(),
- paymentStateContext.getCurrency(),
- paymentStateContext.getProperties(),
- paymentStateContext.getCallContext());
+ paymentStateContext.getPaymentId(),
+ paymentStateContext.getTransactionId(),
+ paymentStateContext.getPaymentMethodId(),
+ paymentStateContext.getAmount(),
+ paymentStateContext.getCurrency(),
+ paymentStateContext.getProperties(),
+ paymentStateContext.getCallContext());
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java
index 1e5454e..e9d3a28 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCaptureOperationCallback.java
@@ -34,15 +34,15 @@ public class RetryCaptureOperationCallback extends RetryOperationCallback {
@Override
protected Payment doCallSpecificOperationCallback() throws PaymentApiException {
return paymentProcessor.createCapture(retryablePaymentStateContext.isApiPayment(),
- retryablePaymentStateContext.getAttemptId(),
- retryablePaymentStateContext.getAccount(),
- retryablePaymentStateContext.getPaymentMethodId(),
- retryablePaymentStateContext.getAmount(),
- retryablePaymentStateContext.getCurrency(),
- retryablePaymentStateContext.getPaymentTransactionExternalKey(),
- false,
- retryablePaymentStateContext.getProperties(),
- retryablePaymentStateContext.getCallContext(),
- retryablePaymentStateContext.getInternalCallContext());
+ retryablePaymentStateContext.getAttemptId(),
+ retryablePaymentStateContext.getAccount(),
+ retryablePaymentStateContext.getPaymentMethodId(),
+ retryablePaymentStateContext.getAmount(),
+ retryablePaymentStateContext.getCurrency(),
+ retryablePaymentStateContext.getPaymentTransactionExternalKey(),
+ false,
+ retryablePaymentStateContext.getProperties(),
+ retryablePaymentStateContext.getCallContext(),
+ retryablePaymentStateContext.getInternalCallContext());
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryEnteringStateCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryEnteringStateCallback.java
index d0247b6..d2d0ce3 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryEnteringStateCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryEnteringStateCallback.java
@@ -42,7 +42,6 @@ public class RetryEnteringStateCallback implements EnteringStateCallback {
@Override
public void enteringState(final State state, final OperationCallback operationCallback, final OperationResult operationResult, final LeavingStateCallback leavingStateCallback) {
-
final PaymentAttemptModelDao attempt = retryablePaymentAutomatonRunner.paymentDao.getPaymentAttempt(paymentStateContext.getAttemptId(), paymentStateContext.internalCallContext);
final UUID transactionId = paymentStateContext.getCurrentTransaction() != null ?
paymentStateContext.getCurrentTransaction().getId() :
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryLeavingStateCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryLeavingStateCallback.java
index 8de364c..afe3140 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryLeavingStateCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryLeavingStateCallback.java
@@ -16,14 +16,17 @@
package org.killbill.billing.payment.core.sm;
+import java.util.UUID;
+
import org.joda.time.DateTime;
import org.killbill.automaton.OperationException;
import org.killbill.automaton.State;
import org.killbill.automaton.State.LeavingStateCallback;
import org.killbill.billing.payment.api.TransactionType;
-import org.killbill.billing.payment.dao.PaymentModelDao;
import org.killbill.billing.payment.dao.PaymentAttemptModelDao;
import org.killbill.billing.payment.dao.PaymentDao;
+import org.killbill.billing.payment.dao.PaymentModelDao;
+import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.dao.PluginPropertySerializer;
import org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException;
@@ -31,7 +34,7 @@ import com.google.common.base.Preconditions;
public class RetryLeavingStateCallback implements LeavingStateCallback {
- private PluginRoutingPaymentAutomatonRunner retryablePaymentAutomatonRunner;
+ private final PluginRoutingPaymentAutomatonRunner retryablePaymentAutomatonRunner;
private final RetryablePaymentStateContext stateContext;
private final State initialState;
private final State retriedState;
@@ -50,37 +53,39 @@ public class RetryLeavingStateCallback implements LeavingStateCallback {
@Override
public void leavingState(final State state) throws OperationException {
-
final DateTime utcNow = retryablePaymentAutomatonRunner.clock.getUTCNow();
- Preconditions.checkState(stateContext.getPaymentExternalKey() != null || /* CAPTURE, PURCHASE, CREDIT calls will provide the paymentId */
- stateContext.getPaymentId() != null);
- if (stateContext.getPaymentExternalKey() == null) {
+ if (stateContext.getPaymentId() != null && stateContext.getPaymentExternalKey() == null) {
final PaymentModelDao payment = paymentDao.getPayment(stateContext.getPaymentId(), stateContext.internalCallContext);
- Preconditions.checkState(payment != null);
+ Preconditions.checkNotNull(payment, "payment cannot be null for id " + stateContext.getPaymentId());
stateContext.setPaymentExternalKey(payment.getExternalKey());
+ } else if (stateContext.getPaymentExternalKey() == null) {
+ stateContext.setPaymentExternalKey(UUID.randomUUID().toString());
+ }
+ if (stateContext.getTransactionId() != null && stateContext.getPaymentTransactionExternalKey() == null) {
+ final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(stateContext.getTransactionId(), stateContext.internalCallContext);
+ Preconditions.checkNotNull(paymentTransactionModelDao, "paymentTransaction cannot be null for id " + stateContext.getTransactionId());
+ stateContext.setPaymentTransactionExternalKey(paymentTransactionModelDao.getTransactionExternalKey());
+ } else if (stateContext.getPaymentTransactionExternalKey() == null) {
+ stateContext.setPaymentTransactionExternalKey(UUID.randomUUID().toString());
}
-
- if (state.getName().equals(initialState.getName()) ||
- state.getName().equals(retriedState.getName())) {
-
+ if (state.getName().equals(initialState.getName()) || state.getName().equals(retriedState.getName())) {
try {
- final byte [] serializedProperties = PluginPropertySerializer.serialize(stateContext.getProperties());
-
+ final byte[] serializedProperties = PluginPropertySerializer.serialize(stateContext.getProperties());
final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(stateContext.getAccount().getId(), stateContext.getPaymentMethodId(),
- utcNow, utcNow, stateContext.getPaymentExternalKey(), null,
- stateContext.paymentTransactionExternalKey, transactionType, initialState.getName(),
+ utcNow, utcNow, stateContext.getPaymentExternalKey(), stateContext.getTransactionId(),
+ stateContext.getPaymentTransactionExternalKey(), transactionType, initialState.getName(),
stateContext.getAmount(), stateContext.getCurrency(),
stateContext.getPaymentControlPluginNames(), serializedProperties);
- retryablePaymentAutomatonRunner.paymentDao.insertPaymentAttemptWithProperties(attempt, stateContext.internalCallContext);
+ retryablePaymentAutomatonRunner.paymentDao.insertPaymentAttemptWithProperties(attempt, stateContext.getInternalCallContext());
+
stateContext.setAttemptId(attempt.getId());
- } catch (PluginPropertySerializerException e) {
+ } catch (final PluginPropertySerializerException e) {
throw new OperationException(e);
}
-
}
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java
index c118d18..dcad8a0 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java
@@ -96,7 +96,7 @@ public abstract class RetryOperationCallback extends OperationCallbackBase<Payme
final PriorPaymentRoutingResult pluginResult;
try {
pluginResult = getPluginResult(retryablePaymentStateContext.getPaymentControlPluginNames(), paymentControlContext);
- if (pluginResult.isAborted()) {
+ if (pluginResult != null && pluginResult.isAborted()) {
// Transition to ABORTED
return PluginDispatcher.createPluginDispatcherReturnType(OperationResult.EXCEPTION);
}
@@ -176,7 +176,7 @@ public abstract class RetryOperationCallback extends OperationCallbackBase<Payme
}
protected void onCompletion(final List<String> paymentControlPluginNames, final PaymentRoutingContext paymentControlContext) {
- for (String pluginName : paymentControlPluginNames) {
+ for (final String pluginName : paymentControlPluginNames) {
final PaymentRoutingPluginApi plugin = paymentControlPluginRegistry.getServiceForName(pluginName);
if (plugin != null) {
try {
@@ -209,17 +209,16 @@ public abstract class RetryOperationCallback extends OperationCallbackBase<Payme
}
private PriorPaymentRoutingResult getPluginResult(final List<String> paymentControlPluginNames, final PaymentRoutingContext paymentControlContextArg) throws PaymentRoutingApiException {
-
// Return as soon as the first plugin aborts, or the last result for the last plugin
PriorPaymentRoutingResult prevResult = null;
PaymentRoutingContext inputPaymentRoutingContext = paymentControlContextArg;
- for (String pluginName : paymentControlPluginNames) {
+ for (final String pluginName : paymentControlPluginNames) {
final PaymentRoutingPluginApi plugin = paymentControlPluginRegistry.getServiceForName(pluginName);
if (plugin == null) {
// First call to plugin, we log warn, if plugin is not registered
- logger.warn("Skipping payment plugin invoice {} when fetching results", pluginName);
+ logger.warn("Skipping unknown payment control plugin {} when fetching results", pluginName);
continue;
}
prevResult = plugin.priorCall(inputPaymentRoutingContext, paymentStateContext.getProperties());
@@ -255,7 +254,7 @@ public abstract class RetryOperationCallback extends OperationCallbackBase<Payme
private DateTime getNextRetryDate(final List<String> paymentControlPluginNames, final PaymentRoutingContext paymentControlContext) {
DateTime candidate = null;
- for (String pluginName : paymentControlPluginNames) {
+ for (final String pluginName : paymentControlPluginNames) {
final PaymentRoutingPluginApi plugin = paymentControlPluginRegistry.getServiceForName(pluginName);
if (plugin != null) {
try {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryStateMachineHelper.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryStateMachineHelper.java
index 0f261cc..30bb1ed 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryStateMachineHelper.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryStateMachineHelper.java
@@ -37,7 +37,6 @@ public class RetryStateMachineHelper {
private static final String INIT_STATE_NAME = "INIT";
private static final String RETRIED_STATE_NAME = "RETRIED";
-
private final StateMachineConfig retryStateMachineConfig;
private final StateMachine retryStateMachine;
private final Operation retryOperation;
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentAttemptModelDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentAttemptModelDao.java
index 85d218a..dfbb709 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentAttemptModelDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentAttemptModelDao.java
@@ -24,7 +24,6 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.killbill.billing.catalog.api.Currency;
-import org.killbill.billing.entity.EntityBase;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.util.dao.TableName;
import org.killbill.billing.util.entity.Entity;
@@ -48,13 +47,13 @@ public class PaymentAttemptModelDao extends EntityModelDaoBase implements Entity
private BigDecimal amount;
private Currency currency;
private String pluginName;
- private byte [] pluginProperties;
+ private byte[] pluginProperties;
public PaymentAttemptModelDao() { /* For the DAO mapper */ }
public PaymentAttemptModelDao(final UUID accountId, final UUID paymentMethodId, final UUID id, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate,
final String paymentExternalKey, final UUID transactionId, final String transactionExternalKey, final TransactionType transactionType,
- final String stateName, final BigDecimal amount, final Currency currency, final String pluginName, final byte [] pluginProperties) {
+ final String stateName, final BigDecimal amount, final Currency currency, final String pluginName, final byte[] pluginProperties) {
super(id, createdDate, updatedDate);
this.accountId = accountId;
this.paymentMethodId = paymentMethodId;
@@ -71,7 +70,7 @@ public class PaymentAttemptModelDao extends EntityModelDaoBase implements Entity
public PaymentAttemptModelDao(final UUID accountId, final UUID paymentMethodId, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate,
final String paymentExternalKey, final UUID transactionId, final String transactionExternalKey, final TransactionType transactionType, final String stateName,
- final BigDecimal amount, final Currency currency, final List<String> paymentControlPluginNames, final byte [] pluginProperties) {
+ final BigDecimal amount, final Currency currency, final List<String> paymentControlPluginNames, final byte[] pluginProperties) {
this(accountId, paymentMethodId, UUID.randomUUID(), createdDate, updatedDate, paymentExternalKey, transactionId, transactionExternalKey, transactionType, stateName,
amount, currency, toPluginNames(paymentControlPluginNames), pluginProperties);
}
@@ -116,11 +115,11 @@ public class PaymentAttemptModelDao extends EntityModelDaoBase implements Entity
this.pluginName = pluginName;
}
- public byte [] getPluginProperties() {
+ public byte[] getPluginProperties() {
return pluginProperties;
}
- public void setPluginProperties(final byte [] pluginProperties) {
+ public void setPluginProperties(final byte[] pluginProperties) {
this.pluginProperties = pluginProperties;
}
@@ -168,7 +167,7 @@ public class PaymentAttemptModelDao extends EntityModelDaoBase implements Entity
if (pluginName == null) {
return ImmutableList.<String>of();
}
- final String [] parts = pluginName.split(",");
+ final String[] parts = pluginName.split(",");
return ImmutableList.<String>copyOf(parts);
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentModelDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentModelDao.java
index 1fffb07..a670f23 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentModelDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentModelDao.java
@@ -21,7 +21,6 @@ import java.util.UUID;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
-import org.killbill.billing.entity.EntityBase;
import org.killbill.billing.payment.api.Payment;
import org.killbill.billing.util.dao.TableName;
import org.killbill.billing.util.entity.dao.EntityModelDao;
@@ -40,7 +39,6 @@ public class PaymentModelDao extends EntityModelDaoBase implements EntityModelDa
private String stateName;
private String lastSuccessStateName;
-
public PaymentModelDao() { /* For the DAO mapper */ }
public PaymentModelDao(final UUID id, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate, final UUID accountId,
diff --git a/payment/src/main/java/org/killbill/billing/payment/glue/PaymentModule.java b/payment/src/main/java/org/killbill/billing/payment/glue/PaymentModule.java
index 72741f9..7bcf32e 100644
--- a/payment/src/main/java/org/killbill/billing/payment/glue/PaymentModule.java
+++ b/payment/src/main/java/org/killbill/billing/payment/glue/PaymentModule.java
@@ -60,6 +60,7 @@ import org.killbill.commons.concurrent.WithProfilingThreadPoolExecutor;
import org.killbill.xmlloader.XMLLoader;
import org.skife.config.ConfigurationObjectFactory;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.io.Resources;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
@@ -76,6 +77,11 @@ public class PaymentModule extends KillBillModule {
public static final String STATE_MACHINE_RETRY = "RetryStateMachine";
public static final String STATE_MACHINE_PAYMENT = "PaymentStateMachine";
+ @VisibleForTesting
+ static final String DEFAULT_STATE_MACHINE_RETRY_XML = "org/killbill/billing/payment/retry/RetryStates.xml";
+ @VisibleForTesting
+ static final String DEFAULT_STATE_MACHINE_PAYMENT_XML = "org/killbill/billing/payment/PaymentStates.xml";
+
public PaymentModule(final KillbillConfigSource configSource) {
super(configSource);
}
@@ -106,11 +112,11 @@ public class PaymentModule extends KillBillModule {
protected void installStateMachines() {
- bind(StateMachineProvider.class).annotatedWith(Names.named(STATE_MACHINE_RETRY)).toInstance(new StateMachineProvider("org/killbill/billing/payment/retry/RetryStates.xml"));
+ bind(StateMachineProvider.class).annotatedWith(Names.named(STATE_MACHINE_RETRY)).toInstance(new StateMachineProvider(DEFAULT_STATE_MACHINE_RETRY_XML));
bind(StateMachineConfig.class).annotatedWith(Names.named(STATE_MACHINE_RETRY)).toProvider(Key.get(StateMachineProvider.class, Names.named(STATE_MACHINE_RETRY)));
bind(RetryStateMachineHelper.class).asEagerSingleton();
- bind(StateMachineProvider.class).annotatedWith(Names.named(STATE_MACHINE_PAYMENT)).toInstance(new StateMachineProvider("org/killbill/billing/payment/PaymentStates.xml"));
+ bind(StateMachineProvider.class).annotatedWith(Names.named(STATE_MACHINE_PAYMENT)).toInstance(new StateMachineProvider(DEFAULT_STATE_MACHINE_PAYMENT_XML));
bind(StateMachineConfig.class).annotatedWith(Names.named(STATE_MACHINE_PAYMENT)).toProvider(Key.get(StateMachineProvider.class, Names.named(STATE_MACHINE_PAYMENT)));
bind(PaymentStateMachineHelper.class).asEagerSingleton();
}
diff --git a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
index e0fc119..b795594 100644
--- a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
@@ -296,7 +296,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, requestedAmount, Currency.USD, paymentExternalKey, transactionExternalKey,
createPropertiesForInvoice(invoice), INVOICE_PAYMENT, callContext);
Assert.fail("Unexpected success");
- } catch (PaymentApiException e) {
+ } catch (final PaymentApiException e) {
assertTrue(e.getCause() instanceof PaymentRoutingApiException);
}
}
@@ -377,7 +377,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
try {
paymentApi.createRefundWithPaymentControl(account, payment.getId(), BigDecimal.TEN, Currency.USD, transactionExternalKey2,
refundProperties, INVOICE_PAYMENT, callContext);
- } catch (PaymentApiException e) {
+ } catch (final PaymentApiException e) {
assertTrue(e.getCause() instanceof PaymentRoutingApiException);
}
}
@@ -472,7 +472,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
paymentApi.createPurchase(account, account.getPaymentMethodId(), payment.getId(), requestedAmount, Currency.AED, paymentExternalKey, transactionExternalKey,
ImmutableList.<PluginProperty>of(), callContext);
Assert.fail("Purchase not succeed after a chargeback");
- } catch (PaymentApiException e) {
+ } catch (final PaymentApiException e) {
Assert.assertTrue(true);
}
}
@@ -532,7 +532,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
try {
paymentApi.createCapture(account, UUID.randomUUID(), requestedAmount, account.getCurrency(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
Assert.fail("Expected capture to fail...");
- } catch (PaymentApiException e) {
+ } catch (final PaymentApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.PAYMENT_NO_SUCH_PAYMENT.getCode());
final Payment latestPayment = paymentApi.getPayment(initialPayment.getId(), false, ImmutableList.<PluginProperty>of(), callContext);
@@ -552,7 +552,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
try {
paymentApi.createCapture(account, initialPayment.getId(), requestedAmount, Currency.AMD, UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
Assert.fail("Expected capture to fail...");
- } catch (PaymentApiException e) {
+ } catch (final PaymentApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.PAYMENT_INVALID_PARAMETER.getCode());
final Payment latestPayment = paymentApi.getPayment(initialPayment.getId(), false, ImmutableList.<PluginProperty>of(), callContext);
@@ -574,13 +574,13 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
// Hack the Database to make it look like it was a failure
paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, "AUTH_ERRORED", null,
payment.getTransactions().get(0).getId(), TransactionStatus.PLUGIN_FAILURE, null, null, null, null, internalCallContext);
- PaymentSqlDao paymentSqlDao = dbi.onDemand(PaymentSqlDao.class);
+ final PaymentSqlDao paymentSqlDao = dbi.onDemand(PaymentSqlDao.class);
paymentSqlDao.updateLastSuccessPaymentStateName(payment.getId().toString(), "AUTH_ERRORED", null, internalCallContext);
try {
paymentApi.createCapture(account, payment.getId(), requestedAmount, Currency.EUR, "tetard", ImmutableList.<PluginProperty>of(), callContext);
Assert.fail("Unexpected success");
- } catch (PaymentApiException e){
+ } catch (final PaymentApiException e){
Assert.assertEquals(e.getCode(), ErrorCode.PAYMENT_INVALID_OPERATION.getCode());
}
}
diff --git a/payment/src/test/java/org/killbill/billing/payment/glue/TestStateMachineProvider.java b/payment/src/test/java/org/killbill/billing/payment/glue/TestStateMachineProvider.java
new file mode 100644
index 0000000..7ab6922
--- /dev/null
+++ b/payment/src/test/java/org/killbill/billing/payment/glue/TestStateMachineProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.payment.glue;
+
+import org.killbill.automaton.StateMachineConfig;
+import org.killbill.billing.payment.PaymentTestSuiteNoDB;
+import org.killbill.billing.payment.glue.PaymentModule.StateMachineProvider;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestStateMachineProvider extends PaymentTestSuiteNoDB {
+
+ @Test(groups = "fast", description = "https://github.com/killbill/killbill/issues/226")
+ public void testStateMachineProvider() throws Exception {
+ final StateMachineProvider retryStateMachineProvider = new StateMachineProvider(PaymentModule.DEFAULT_STATE_MACHINE_RETRY_XML);
+ final StateMachineConfig retryStateMachineConfig = retryStateMachineProvider.get();
+ Assert.assertEquals(retryStateMachineConfig.getStateMachines().length, 1);
+
+ final StateMachineProvider paymentStateMachineProvider = new StateMachineProvider(PaymentModule.DEFAULT_STATE_MACHINE_PAYMENT_XML);
+ final StateMachineConfig paymentStateMachineConfig = paymentStateMachineProvider.get();
+ Assert.assertEquals(paymentStateMachineConfig.getStateMachines().length, 8);
+ }
+}
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index e3d87cf..2f8247c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>org.kill-bill.billing</groupId>
- <version>0.9.2</version>
+ <version>0.9.5-SNAPSHOT</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.12.2-SNAPSHOT</version>
diff --git a/profiles/killbill/src/main/webapp/api.html b/profiles/killbill/src/main/webapp/api.html
index 0ce3e81..8cd886f 100644
--- a/profiles/killbill/src/main/webapp/api.html
+++ b/profiles/killbill/src/main/webapp/api.html
@@ -43,14 +43,9 @@
<script src='lib/swagger-oauth.js' type='text/javascript'></script>
<script type="text/javascript">
$(function () {
- var url = window.location.search.match(/url=([^&]+)/);
- if (url && url.length > 1) {
- url = url[1];
- } else {
- url = "http://127.0.0.1:8080/api-docs";
- }
+ var url = window.location.href.replace(/(.*)(\/[^\/]*?)$/, '$1/api-docs')
window.swaggerUi = new SwaggerUi({
- url: url,
+ url: (url || "http://127.0.0.1:8080/api-docs"),
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
onComplete: function(swaggerApi, swaggerUi){
diff --git a/profiles/killpay/src/main/webapp/api.html b/profiles/killpay/src/main/webapp/api.html
index 0ce3e81..8cd886f 100644
--- a/profiles/killpay/src/main/webapp/api.html
+++ b/profiles/killpay/src/main/webapp/api.html
@@ -43,14 +43,9 @@
<script src='lib/swagger-oauth.js' type='text/javascript'></script>
<script type="text/javascript">
$(function () {
- var url = window.location.search.match(/url=([^&]+)/);
- if (url && url.length > 1) {
- url = url[1];
- } else {
- url = "http://127.0.0.1:8080/api-docs";
- }
+ var url = window.location.href.replace(/(.*)(\/[^\/]*?)$/, '$1/api-docs')
window.swaggerUi = new SwaggerUi({
- url: url,
+ url: (url || "http://127.0.0.1:8080/api-docs"),
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
onComplete: function(swaggerApi, swaggerUi){
diff --git a/util/src/main/java/org/killbill/billing/util/config/PaymentConfig.java b/util/src/main/java/org/killbill/billing/util/config/PaymentConfig.java
index 0b5826d..86a0014 100644
--- a/util/src/main/java/org/killbill/billing/util/config/PaymentConfig.java
+++ b/util/src/main/java/org/killbill/billing/util/config/PaymentConfig.java
@@ -81,8 +81,8 @@ public interface PaymentConfig extends KillbillConfig {
public TimeSpan getJanitorRunningRate();
@Config("org.killbill.payment.invoice.plugin")
- @Default("__INVOICE_PAYMENT_CONTROL_PLUGIN__")
- @Description("Whether the payment subsystem is off")
+ @Default("")
+ @Description("Default payment control plugin names")
public List<String> getPaymentControlPluginNames();
@Config("org.killbill.payment.off")
diff --git a/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java b/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java
index 55ca1d9..149d852 100644
--- a/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java
+++ b/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java
@@ -18,15 +18,15 @@ package org.killbill.billing.util.dao;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.regex.Pattern;
import org.antlr.stringtemplate.StringTemplateGroup;
+import org.killbill.billing.util.UtilTestSuiteNoDB;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import org.killbill.billing.util.UtilTestSuiteNoDB;
-
import com.google.common.collect.ImmutableMap;
public class TestStringTemplateInheritance extends UtilTestSuiteNoDB {
@@ -66,127 +66,131 @@ public class TestStringTemplateInheritance extends UtilTestSuiteNoDB {
Assert.assertEquals(kombucha.getInstanceOf("isIsTimeForKombucha").toString(), "select hour(current_timestamp()) = 17 as is_time;");
// Verify inherited templates
- Assert.assertEquals(kombucha.getInstanceOf("getById").toString(), "select\n" +
- " t.record_id\n" +
- ", t.id\n" +
- ", t.tea\n" +
- ", t.mushroom\n" +
- ", t.sugar\n" +
- ", t.account_record_id\n" +
- ", t.tenant_record_id\n" +
- "from kombucha t\n" +
- "where t.id = :id\n" +
- "and t.tenant_record_id = :tenantRecordId\n" +
+ assertPattern(kombucha.getInstanceOf("getById").toString(), "select\r?\n" +
+ " t.record_id\r?\n" +
+ ", t.id\r?\n" +
+ ", t.tea\r?\n" +
+ ", t.mushroom\r?\n" +
+ ", t.sugar\r?\n" +
+ ", t.account_record_id\r?\n" +
+ ", t.tenant_record_id\r?\n" +
+ "from kombucha t\r?\n" +
+ "where t.id = :id\r?\n" +
+ "and t.tenant_record_id = :tenantRecordId\r?\n" +
+ ";");
+ assertPattern(kombucha.getInstanceOf("getByRecordId").toString(), "select\r?\n" +
+ " t.record_id\r?\n" +
+ ", t.id\r?\n" +
+ ", t.tea\r?\n" +
+ ", t.mushroom\r?\n" +
+ ", t.sugar\r?\n" +
+ ", t.account_record_id\r?\n" +
+ ", t.tenant_record_id\r?\n" +
+ "from kombucha t\r?\n" +
+ "where t.record_id = :recordId\r?\n" +
+ "and t.tenant_record_id = :tenantRecordId\r?\n" +
";");
- Assert.assertEquals(kombucha.getInstanceOf("getByRecordId").toString(), "select\n" +
- " t.record_id\n" +
- ", t.id\n" +
- ", t.tea\n" +
- ", t.mushroom\n" +
- ", t.sugar\n" +
- ", t.account_record_id\n" +
- ", t.tenant_record_id\n" +
- "from kombucha t\n" +
- "where t.record_id = :recordId\n" +
- "and t.tenant_record_id = :tenantRecordId\n" +
- ";");
- Assert.assertEquals(kombucha.getInstanceOf("getRecordId").toString(), "select\n" +
- " t.record_id\n" +
- "from kombucha t\n" +
- "where t.id = :id\n" +
- "and t.tenant_record_id = :tenantRecordId\n" +
- ";");
- Assert.assertEquals(kombucha.getInstanceOf("getHistoryRecordId").toString(), "select\n" +
- " max(t.record_id)\n" +
- "from kombucha_history t\n" +
- "where t.target_record_id = :targetRecordId\n" +
- "and t.tenant_record_id = :tenantRecordId\n" +
- ";");
- Assert.assertEquals(kombucha.getInstanceOf("getAll").toString(), "select\n" +
- " t.record_id\n" +
- ", t.id\n" +
- ", t.tea\n" +
- ", t.mushroom\n" +
- ", t.sugar\n" +
- ", t.account_record_id\n" +
- ", t.tenant_record_id\n" +
- "from kombucha t\n" +
- "where t.tenant_record_id = :tenantRecordId\n" +
- "order by t.record_id ASC\n" +
- ";");
- Assert.assertEquals(kombucha.getInstanceOf("get", ImmutableMap.<String, String>of("orderBy", "record_id", "offset", "3", "rowCount", "12")).toString(), "select\n" +
- " t.record_id\n" +
- ", t.id\n" +
- ", t.tea\n" +
- ", t.mushroom\n" +
- ", t.sugar\n" +
- ", t.account_record_id\n" +
- ", t.tenant_record_id\n" +
- "from kombucha t\n" +
- "where t.tenant_record_id = :tenantRecordId\n" +
- "order by t.record_id\n" +
- "limit :offset, :rowCount\n" +
- ";");
- Assert.assertEquals(kombucha.getInstanceOf("test").toString(), "select\n" +
- " t.record_id\n" +
- ", t.id\n" +
- ", t.tea\n" +
- ", t.mushroom\n" +
- ", t.sugar\n" +
- ", t.account_record_id\n" +
- ", t.tenant_record_id\n" +
- "from kombucha t\n" +
- "where t.tenant_record_id = :tenantRecordId\n" +
- "limit 1\n" +
- ";");
- Assert.assertEquals(kombucha.getInstanceOf("addHistoryFromTransaction").toString(), "insert into kombucha_history (\n" +
- " id\n" +
- ", target_record_id\n" +
- ", change_type\n" +
- ", tea\n" +
- ", mushroom\n" +
- ", sugar\n" +
- ", account_record_id\n" +
- ", tenant_record_id\n" +
- ")\n" +
- "values (\n" +
- " :id\n" +
- ", :targetRecordId\n" +
- ", :changeType\n" +
- ", :tea\n" +
- ", :mushroom\n" +
- ", :sugar\n" +
- ", :accountRecordId\n" +
- ", :tenantRecordId\n" +
- ")\n" +
- ";");
+ assertPattern(kombucha.getInstanceOf("getRecordId").toString(), "select\r?\n" +
+ " t.record_id\r?\n" +
+ "from kombucha t\r?\n" +
+ "where t.id = :id\r?\n" +
+ "and t.tenant_record_id = :tenantRecordId\r?\n" +
+ ";");
+ assertPattern(kombucha.getInstanceOf("getHistoryRecordId").toString(), "select\r?\n" +
+ " max\\(t.record_id\\)\r?\n" +
+ "from kombucha_history t\r?\n" +
+ "where t.target_record_id = :targetRecordId\r?\n" +
+ "and t.tenant_record_id = :tenantRecordId\r?\n" +
+ ";");
+ assertPattern(kombucha.getInstanceOf("getAll").toString(), "select\r?\n" +
+ " t.record_id\r?\n" +
+ ", t.id\r?\n" +
+ ", t.tea\r?\n" +
+ ", t.mushroom\r?\n" +
+ ", t.sugar\r?\n" +
+ ", t.account_record_id\r?\n" +
+ ", t.tenant_record_id\r?\n" +
+ "from kombucha t\r?\n" +
+ "where t.tenant_record_id = :tenantRecordId\r?\n" +
+ "order by t.record_id ASC\r?\n" +
+ ";");
+ assertPattern(kombucha.getInstanceOf("get", ImmutableMap.<String, String>of("orderBy", "record_id", "offset", "3", "rowCount", "12")).toString(), "select\r?\n" +
+ " t.record_id\r?\n" +
+ ", t.id\r?\n" +
+ ", t.tea\r?\n" +
+ ", t.mushroom\r?\n" +
+ ", t.sugar\r?\n" +
+ ", t.account_record_id\r?\n" +
+ ", t.tenant_record_id\r?\n" +
+ "from kombucha t\r?\n" +
+ "where t.tenant_record_id = :tenantRecordId\r?\n" +
+ "order by t.record_id\r?\n" +
+ "limit :offset, :rowCount\r?\n" +
+ ";");
+ assertPattern(kombucha.getInstanceOf("test").toString(), "select\r?\n" +
+ " t.record_id\r?\n" +
+ ", t.id\r?\n" +
+ ", t.tea\r?\n" +
+ ", t.mushroom\r?\n" +
+ ", t.sugar\r?\n" +
+ ", t.account_record_id\r?\n" +
+ ", t.tenant_record_id\r?\n" +
+ "from kombucha t\r?\n" +
+ "where t.tenant_record_id = :tenantRecordId\r?\n" +
+ "limit 1\r?\n" +
+ ";");
+ assertPattern(kombucha.getInstanceOf("addHistoryFromTransaction").toString(), "insert into kombucha_history \\(\r?\n" +
+ " id\r?\n" +
+ ", target_record_id\r?\n" +
+ ", change_type\r?\n" +
+ ", tea\r?\n" +
+ ", mushroom\r?\n" +
+ ", sugar\r?\n" +
+ ", account_record_id\r?\n" +
+ ", tenant_record_id\r?\n" +
+ "\\)\r?\n" +
+ "values \\(\r?\n" +
+ " :id\r?\n" +
+ ", :targetRecordId\r?\n" +
+ ", :changeType\r?\n" +
+ ", :tea\r?\n" +
+ ", :mushroom\r?\n" +
+ ", :sugar\r?\n" +
+ ", :accountRecordId\r?\n" +
+ ", :tenantRecordId\r?\n" +
+ "\\)\r?\n" +
+ ";");
+
+ assertPattern(kombucha.getInstanceOf("insertAuditFromTransaction").toString(), "insert into audit_log \\(\r?\n" +
+ "id\r?\n" +
+ ", table_name\r?\n" +
+ ", target_record_id\r?\n" +
+ ", change_type\r?\n" +
+ ", created_by\r?\n" +
+ ", reason_code\r?\n" +
+ ", comments\r?\n" +
+ ", user_token\r?\n" +
+ ", created_date\r?\n" +
+ ", account_record_id\r?\n" +
+ ", tenant_record_id\r?\n" +
+ "\\)\r?\n" +
+ "values \\(\r?\n" +
+ " :id\r?\n" +
+ ", :tableName\r?\n" +
+ ", :targetRecordId\r?\n" +
+ ", :changeType\r?\n" +
+ ", :createdBy\r?\n" +
+ ", :reasonCode\r?\n" +
+ ", :comments\r?\n" +
+ ", :userToken\r?\n" +
+ ", :createdDate\r?\n" +
+ ", :accountRecordId\r?\n" +
+ ", :tenantRecordId\r?\n" +
+ "\\)\r?\n" +
+ ";");
+ }
- Assert.assertEquals(kombucha.getInstanceOf("insertAuditFromTransaction").toString(), "insert into audit_log (\n" +
- "id\n" +
- ", table_name\n" +
- ", target_record_id\n" +
- ", change_type\n" +
- ", created_by\n" +
- ", reason_code\n" +
- ", comments\n" +
- ", user_token\n" +
- ", created_date\n" +
- ", account_record_id\n" +
- ", tenant_record_id\n" +
- ")\n" +
- "values (\n" +
- " :id\n" +
- ", :tableName\n" +
- ", :targetRecordId\n" +
- ", :changeType\n" +
- ", :createdBy\n" +
- ", :reasonCode\n" +
- ", :comments\n" +
- ", :userToken\n" +
- ", :createdDate\n" +
- ", :accountRecordId\n" +
- ", :tenantRecordId\n" +
- ")\n" +
- ";");
+ private void assertPattern(final String actual, final String expected) {
+ Assert.assertTrue(Pattern.compile(expected).matcher(actual).find(), String.format("Expected to see:\n%s\nin:\n%s", expected, actual));
}
}