killbill-memoizeit
Changes
jaxrs/pom.xml 1(+0 -1)
payment/pom.xml 1(+0 -1)
payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCompletionOperationCallback.java 7(+4 -3)
pom.xml 2(+1 -1)
profiles/killbill/src/main/java/org/killbill/billing/server/listeners/KillbillGuiceListener.java 3(+3 -0)
profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java 2(+2 -0)
profiles/killbill/src/main/java/org/killbill/billing/server/profiling/ProfilingFilter.java 72(+72 -0)
profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java 2(+2 -0)
util/pom.xml 4(+4 -0)
Details
jaxrs/pom.xml 1(+0 -1)
diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index 12fe841..716d1ed 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -88,7 +88,6 @@
<dependency>
<groupId>org.kill-bill.billing</groupId>
<artifactId>killbill-platform-base</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.kill-bill.billing</groupId>
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ProfilingDataJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ProfilingDataJson.java
new file mode 100644
index 0000000..96d6096
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ProfilingDataJson.java
@@ -0,0 +1,52 @@
+/*
+ * 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.jaxrs.json;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import org.killbill.billing.platform.profiling.ProfilingData;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ProfilingDataJson {
+
+ private final Map<String, List<Long>> rawData;
+ private final String createdUri;
+
+ @JsonCreator
+ public ProfilingDataJson(@JsonProperty("createdUri") final String createdUri,
+ @JsonProperty("rawData") final Map<String, List<Long>> rawData) {
+ this.createdUri = createdUri;
+ this.rawData = rawData;
+ }
+
+ public ProfilingDataJson(final ProfilingData data, final URI uri) {
+ this(uri.getPath(), data.getRawData());
+ }
+
+ public Map<String, List<Long>> getRawData() {
+ return rawData;
+ }
+
+ public String getCreatedUri() {
+ return createdUri;
+ }
+}
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 13dd28e..9c656a5 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
@@ -20,10 +20,8 @@ package org.killbill.billing.jaxrs.resources;
import java.io.IOException;
import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URI;
-import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -49,7 +47,6 @@ import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountUserApi;
-import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoicePayment;
import org.killbill.billing.invoice.api.InvoicePaymentType;
import org.killbill.billing.jaxrs.json.CustomFieldJson;
@@ -59,11 +56,13 @@ import org.killbill.billing.jaxrs.util.Context;
import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
import org.killbill.billing.payment.api.Payment;
import org.killbill.billing.payment.api.PaymentApi;
-import org.killbill.billing.payment.api.PaymentTransaction;
import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PaymentOptions;
+import org.killbill.billing.payment.api.PaymentTransaction;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionType;
+import org.killbill.billing.platform.profiling.Profiling;
+import org.killbill.billing.platform.profiling.ProfilingData.ProfilingDataOutput;
import org.killbill.billing.util.api.AuditUserApi;
import org.killbill.billing.util.api.CustomFieldApiException;
import org.killbill.billing.util.api.CustomFieldUserApi;
@@ -331,7 +330,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
return null;
}
- protected Iterable<PluginProperty> extractPluginProperties(@Nullable final Iterable<String> pluginProperties, PluginProperty...additionalProperties) {
+ protected Iterable<PluginProperty> extractPluginProperties(@Nullable final Iterable<String> pluginProperties, PluginProperty... additionalProperties) {
final Collection<PluginProperty> properties = new LinkedList<PluginProperty>();
if (pluginProperties == null) {
return properties;
@@ -343,7 +342,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
final String value = property.size() == 1 ? null : Joiner.on("=").join(property.subList(1, property.size()));
properties.add(new PluginProperty(key, value, false));
}
- for (PluginProperty cur : additionalProperties) {
+ for (PluginProperty cur : additionalProperties) {
properties.add(cur);
}
return properties;
@@ -360,16 +359,16 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
final UUID paymentMethodId = externalPayment ? null : account.getPaymentMethodId();
return paymentApi.createPurchaseWithPaymentControl(account, paymentMethodId, null, amountToPay, account.getCurrency(), paymentExternalKey, transactionExternalKey,
- properties, createInvoicePaymentControlPluginApiPaymentOptions(externalPayment), callContext);
+ properties, createInvoicePaymentControlPluginApiPaymentOptions(externalPayment), callContext);
}
-
protected PaymentOptions createInvoicePaymentControlPluginApiPaymentOptions(final boolean isExternalPayment) {
return new PaymentOptions() {
@Override
public boolean isExternalPayment() {
return isExternalPayment;
}
+
@Override
public String getPaymentControlPluginName() {
/* Contract with plugin */
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
index cd1842b..7cc3044 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
@@ -23,8 +23,11 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
+import org.killbill.billing.jaxrs.json.ProfilingDataJson;
import org.killbill.billing.jaxrs.resources.JaxRsResourceBase;
import org.killbill.billing.jaxrs.resources.JaxrsResource;
+import org.killbill.billing.platform.profiling.Profiling;
+import org.killbill.billing.platform.profiling.ProfilingData;
public class JaxrsUriBuilder {
@@ -36,7 +39,6 @@ public class JaxrsUriBuilder {
.port(uriInfo.getAbsolutePath().getPort());
final URI location = objectId != null ? uriBuilder.build(objectId) : uriBuilder.build();
-
return Response.created(location).build();
}
@@ -64,12 +66,15 @@ public class JaxrsUriBuilder {
tmp.append(UriBuilder.fromResource(theClass).path(theClass, getMethodName).build(objectId).toString());
final URI newUriFromResource = UriBuilder.fromUri(tmp.toString()).build();
final Response.ResponseBuilder ri = Response.created(newUriFromResource);
- return ri.entity(new Object() {
+
+ final ProfilingData profilingData = Profiling.getPerThreadProfilingData();
+ final Object obj = profilingData == null ? new Object() {
@SuppressWarnings(value = "all")
public URI getUri() {
-
return newUriFromResource;
}
- }).build();
+ } : new ProfilingDataJson(profilingData, newUriFromResource);
+
+ return ri.entity(obj).build();
}
}
payment/pom.xml 1(+0 -1)
diff --git a/payment/pom.xml b/payment/pom.xml
index e0064dc..00e0c82 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -101,7 +101,6 @@
<dependency>
<groupId>org.kill-bill.billing</groupId>
<artifactId>killbill-platform-base</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.kill-bill.billing</groupId>
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
index b4f3698..c9231d0 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentGatewayProcessor.java
@@ -37,6 +37,7 @@ import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.dao.PaymentDao;
import org.killbill.billing.payment.dispatcher.PluginDispatcher;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
import org.killbill.billing.payment.plugin.api.GatewayNotification;
import org.killbill.billing.payment.plugin.api.HostedPaymentPageFormDescriptor;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
@@ -81,18 +82,36 @@ public class PaymentGatewayProcessor extends ProcessorBase {
this.paymentPluginNotificationDispatcher = new PluginDispatcher<GatewayNotification>(paymentPluginTimeoutSec, executor);
}
+ public GatewayNotification processNotification(final String notification, final String pluginName, final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
+ return dispatchWithExceptionHandling(null,
+ new Callable<PluginDispatcherReturnType<GatewayNotification>>() {
+ @Override
+ public PluginDispatcherReturnType<GatewayNotification> call() throws PaymentApiException {
+ final PaymentPluginApi plugin = getPaymentPluginApi(pluginName);
+ try {
+ final GatewayNotification result = plugin.processNotification(notification, properties, callContext);
+ return PluginDispatcher.createPluginDispatcherReturnType(result);
+ } catch (PaymentPluginApiException e) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e.getErrorMessage());
+ }
+ }
+ }, paymentPluginNotificationDispatcher);
+ }
+
+
+
public HostedPaymentPageFormDescriptor buildFormDescriptor(final Account account, final Iterable<PluginProperty> customFields, final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
return dispatchWithExceptionHandling(account,
new CallableWithAccountLock<HostedPaymentPageFormDescriptor, PaymentApiException>(locker,
account.getExternalKey(),
- new WithAccountLockCallback<HostedPaymentPageFormDescriptor, PaymentApiException>() {
-
+ new WithAccountLockCallback<PluginDispatcherReturnType<HostedPaymentPageFormDescriptor>, PaymentApiException>() {
@Override
- public HostedPaymentPageFormDescriptor doOperation() throws PaymentApiException {
+ public PluginDispatcherReturnType<HostedPaymentPageFormDescriptor> doOperation() throws PaymentApiException {
final PaymentPluginApi plugin = getPaymentProviderPlugin(account, internalCallContext);
try {
- return plugin.buildFormDescriptor(account.getId(), customFields, properties, callContext);
+ final HostedPaymentPageFormDescriptor result = plugin.buildFormDescriptor(account.getId(), customFields, properties, callContext);
+ return PluginDispatcher.createPluginDispatcherReturnType(result);
} catch (final RuntimeException e) {
throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, Objects.firstNonNull(e.getMessage(), ""));
} catch (final PaymentPluginApiException e) {
@@ -103,22 +122,7 @@ public class PaymentGatewayProcessor extends ProcessorBase {
paymentPluginFormDispatcher);
}
- public GatewayNotification processNotification(final String notification, final String pluginName, final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
- return dispatchWithExceptionHandling(null,
- new Callable<GatewayNotification>() {
- @Override
- public GatewayNotification call() throws PaymentApiException {
- final PaymentPluginApi plugin = getPaymentPluginApi(pluginName);
- try {
- return plugin.processNotification(notification, properties, callContext);
- } catch (PaymentPluginApiException e) {
- throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e.getErrorMessage());
- }
- }
- }, paymentPluginNotificationDispatcher);
- }
-
- private static <ReturnType> ReturnType dispatchWithExceptionHandling(@Nullable final Account account, final Callable<ReturnType> callable, PluginDispatcher<ReturnType> pluginFormDispatcher) throws PaymentApiException {
+ private static <ReturnType> ReturnType dispatchWithExceptionHandling(@Nullable final Account account, final Callable<PluginDispatcherReturnType<ReturnType>> callable, PluginDispatcher<ReturnType> pluginFormDispatcher) throws PaymentApiException {
final UUID accountId = account != null ? account.getId() : null;
final String accountExternalKey = account != null ? account.getExternalKey() : "";
try {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
index 69ff4a7..e479bae 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
@@ -41,6 +41,8 @@ import org.killbill.billing.payment.api.PaymentMethodPlugin;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.dao.PaymentDao;
import org.killbill.billing.payment.dao.PaymentMethodModelDao;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
import org.killbill.billing.payment.plugin.api.PaymentMethodInfoPlugin;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.payment.plugin.api.PaymentPluginApiException;
@@ -54,9 +56,9 @@ import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.EntityPaginationBuilder;
import org.killbill.billing.util.entity.dao.DefaultPaginationHelper.SourcePaginationBuilder;
-import org.killbill.bus.api.PersistentBus;
import org.killbill.clock.Clock;
import org.killbill.commons.locker.GlobalLocker;
+import org.killbill.commons.locker.LockFailedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -93,10 +95,10 @@ public class PaymentMethodProcessor extends ProcessorBase {
final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext context)
throws PaymentApiException {
try {
- return new WithAccountLock<UUID, PaymentApiException>().processAccountWithLock(locker, account.getExternalKey(), new WithAccountLockCallback<UUID, PaymentApiException>() {
+ final PluginDispatcherReturnType<UUID> result = new WithAccountLock<UUID, PaymentApiException>().processAccountWithLock(locker, account.getExternalKey(), new WithAccountLockCallback<PluginDispatcherReturnType<UUID>, PaymentApiException>() {
@Override
- public UUID doOperation() throws PaymentApiException {
+ public PluginDispatcherReturnType<UUID> doOperation() throws PaymentApiException {
PaymentMethod pm = null;
PaymentPluginApi pluginApi;
try {
@@ -116,9 +118,10 @@ public class PaymentMethodProcessor extends ProcessorBase {
} catch (final AccountApiException e) {
throw new PaymentApiException(e);
}
- return pm.getId();
+ return PluginDispatcher.createPluginDispatcherReturnType(pm.getId());
}
});
+ return result.getReturnType();
} catch (Exception e) {
throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, Objects.firstNonNull(e.getMessage(), ""));
}
@@ -160,7 +163,6 @@ public class PaymentMethodProcessor extends ProcessorBase {
return buildDefaultPaymentMethod(paymentMethodModel, withPluginInfo, properties, tenantContext, context);
}
-
private PaymentMethod buildDefaultPaymentMethod(final PaymentMethodModelDao paymentMethodModelDao, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext context) throws PaymentApiException {
final PaymentMethodPlugin paymentMethodPlugin;
if (withPluginInfo) {
@@ -312,10 +314,10 @@ public class PaymentMethodProcessor extends ProcessorBase {
final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext context)
throws PaymentApiException {
try {
- new WithAccountLock<Void, PaymentApiException>().processAccountWithLock(locker, account.getExternalKey(), new WithAccountLockCallback<Void, PaymentApiException>() {
+ new WithAccountLock<Void, PaymentApiException>().processAccountWithLock(locker, account.getExternalKey(), new WithAccountLockCallback<PluginDispatcherReturnType<Void>, PaymentApiException>() {
@Override
- public Void doOperation() throws PaymentApiException {
+ public PluginDispatcherReturnType<Void> doOperation() throws PaymentApiException {
final PaymentMethodModelDao paymentMethodModel = paymentDao.getPaymentMethod(paymentMethodId, context);
if (paymentMethodModel == null) {
throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
@@ -338,7 +340,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
final PaymentPluginApi pluginApi = getPluginApi(paymentMethodId, context);
pluginApi.deletePaymentMethod(account.getId(), paymentMethodId, properties, callContext);
paymentDao.deletedPaymentMethod(paymentMethodId, context);
- return null;
+ return PluginDispatcher.createPluginDispatcherReturnType(null);
} catch (final PaymentPluginApiException e) {
log.warn("Error deleting payment method " + paymentMethodId, e);
throw new PaymentApiException(ErrorCode.PAYMENT_DEL_PAYMENT_METHOD, account.getId(), e.getErrorMessage());
@@ -355,10 +357,10 @@ public class PaymentMethodProcessor extends ProcessorBase {
public void setDefaultPaymentMethod(final Account account, final UUID paymentMethodId, final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext context)
throws PaymentApiException {
try {
- new WithAccountLock<Void, PaymentApiException>().processAccountWithLock(locker, account.getExternalKey(), new WithAccountLockCallback<Void, PaymentApiException>() {
+ new WithAccountLock<Void, PaymentApiException>().processAccountWithLock(locker, account.getExternalKey(), new WithAccountLockCallback<PluginDispatcherReturnType<Void>, PaymentApiException>() {
@Override
- public Void doOperation() throws PaymentApiException {
+ public PluginDispatcherReturnType<Void> doOperation() throws PaymentApiException {
final PaymentMethodModelDao paymentMethodModel = paymentDao.getPaymentMethod(paymentMethodId, context);
if (paymentMethodModel == null) {
throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
@@ -369,7 +371,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
pluginApi.setDefaultPaymentMethod(account.getId(), paymentMethodId, properties, callContext);
accountInternalApi.updatePaymentMethod(account.getId(), paymentMethodId, context);
- return null;
+ return PluginDispatcher.createPluginDispatcherReturnType(null);
} catch (final PaymentPluginApiException e) {
throw new PaymentApiException(ErrorCode.PAYMENT_UPD_PAYMENT_METHOD, account.getId(), e.getErrorMessage());
} catch (final AccountApiException e) {
@@ -419,10 +421,9 @@ public class PaymentMethodProcessor extends ProcessorBase {
}
try {
- return new WithAccountLock<List<PaymentMethod>, PaymentApiException>().processAccountWithLock(locker, account.getExternalKey(), new WithAccountLockCallback<List<PaymentMethod>, PaymentApiException>() {
-
+ final PluginDispatcherReturnType<List<PaymentMethod>> result = new WithAccountLock<List<PaymentMethod>, PaymentApiException>().processAccountWithLock(locker, account.getExternalKey(), new WithAccountLockCallback<PluginDispatcherReturnType<List<PaymentMethod>>, PaymentApiException>() {
@Override
- public List<PaymentMethod> doOperation() throws PaymentApiException {
+ public PluginDispatcherReturnType<List<PaymentMethod>> doOperation() throws PaymentApiException {
UUID defaultPaymentMethodId = null;
@@ -433,7 +434,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
final UUID paymentMethodId = cur.getPaymentMethodId() != null ? cur.getPaymentMethodId() : UUID.randomUUID();
// TODO paymentMethod externalKey seems broken here.
final PaymentMethod input = new DefaultPaymentMethod(paymentMethodId, paymentMethodId.toString(), account.getId(), pluginName);
- final PaymentMethodModelDao pmModel = new PaymentMethodModelDao(input.getId(), input.getExternalKey(), input.getCreatedDate(), input.getUpdatedDate(),
+ final PaymentMethodModelDao pmModel = new PaymentMethodModelDao(input.getId(), input.getExternalKey(), input.getCreatedDate(), input.getUpdatedDate(),
input.getAccountId(), input.getPluginName(), input.isActive());
finalPaymentMethods.add(pmModel);
@@ -451,27 +452,28 @@ public class PaymentMethodProcessor extends ProcessorBase {
pluginName,
finalPaymentMethods,
context);
+
try {
pluginApi.resetPaymentMethods(account.getId(), pluginPmsWithId, properties, callContext);
} catch (final PaymentPluginApiException e) {
log.warn("Error resetting payment methods for account " + account.getId() + " and plugin " + pluginName, e);
throw new PaymentApiException(ErrorCode.PAYMENT_REFRESH_PAYMENT_METHOD, account.getId(), e.getErrorMessage());
}
-
try {
updateDefaultPaymentMethodIfNeeded(pluginName, account, defaultPaymentMethodId, context);
} catch (final AccountApiException e) {
throw new PaymentApiException(e);
}
-
- return ImmutableList.<PaymentMethod>copyOf(Collections2.transform(refreshedPaymentMethods, new Function<PaymentMethodModelDao, PaymentMethod>() {
+ final List<PaymentMethod> result = ImmutableList.<PaymentMethod>copyOf(Collections2.transform(refreshedPaymentMethods, new Function<PaymentMethodModelDao, PaymentMethod>() {
@Override
public PaymentMethod apply(final PaymentMethodModelDao input) {
return new DefaultPaymentMethod(input, null);
}
}));
+ return PluginDispatcher.createPluginDispatcherReturnType(result);
}
});
+ return result.getReturnType();
} catch (Exception e) {
throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, Objects.firstNonNull(e.getMessage(), ""));
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java b/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
index 0a8db62..02295f3 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/ProcessorBase.java
@@ -39,6 +39,7 @@ import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.dao.PaymentDao;
import org.killbill.billing.payment.dao.PaymentMethodModelDao;
import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.tag.TagInternalApi;
import org.killbill.billing.util.api.TagApiException;
@@ -175,33 +176,34 @@ public abstract class ProcessorBase {
// TODO Rename - there is no lock!
- public interface WithAccountLockCallback<ReturnType, ExceptionType extends Exception> {
- public ReturnType doOperation() throws ExceptionType;
+ public interface WithAccountLockCallback<PluginDispatcherReturnType, ExceptionType extends Exception> {
+ public PluginDispatcherReturnType doOperation() throws ExceptionType;
}
- public static class CallableWithAccountLock<ReturnType, ExceptionType extends Exception> implements Callable<ReturnType> {
+ public static class CallableWithAccountLock<ReturnType, ExceptionType extends Exception> implements Callable<PluginDispatcherReturnType<ReturnType>> {
private final GlobalLocker locker;
private final String accountExternalKey;
- private final WithAccountLockCallback<ReturnType, ExceptionType> callback;
+ private final WithAccountLockCallback<PluginDispatcherReturnType<ReturnType>, ExceptionType> callback;
+
public CallableWithAccountLock(final GlobalLocker locker,
final String accountExternalKey,
- final WithAccountLockCallback<ReturnType, ExceptionType> callback) {
+ final WithAccountLockCallback<PluginDispatcherReturnType<ReturnType>, ExceptionType> callback) {
this.locker = locker;
this.accountExternalKey = accountExternalKey;
this.callback = callback;
}
@Override
- public ReturnType call() throws ExceptionType, LockFailedException {
+ public PluginDispatcherReturnType<ReturnType> call() throws ExceptionType, LockFailedException {
return new WithAccountLock<ReturnType, ExceptionType>().processAccountWithLock(locker, accountExternalKey, callback);
}
}
- public static class WithAccountLock<T, ExceptionType extends Exception> {
+ public static class WithAccountLock<ReturnType, ExceptionType extends Exception> {
- public T processAccountWithLock(final GlobalLocker locker, final String accountExternalKey, final WithAccountLockCallback<T,ExceptionType > callback)
+ public PluginDispatcherReturnType<ReturnType> processAccountWithLock(final GlobalLocker locker, final String accountExternalKey, final WithAccountLockCallback<PluginDispatcherReturnType<ReturnType>, ExceptionType > callback)
throws ExceptionType, LockFailedException {
GlobalLock lock = null;
try {
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 68cf540..d4da958 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
@@ -27,6 +27,7 @@ import org.killbill.billing.account.api.Account;
import org.killbill.billing.payment.core.ProcessorBase.CallableWithAccountLock;
import org.killbill.billing.payment.core.ProcessorBase.WithAccountLockCallback;
import org.killbill.billing.payment.dispatcher.PluginDispatcher;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
import org.killbill.commons.locker.GlobalLocker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,12 +54,12 @@ public abstract class OperationCallbackBase {
// The dispatcher may throw a TimeoutException, ExecutionException, or InterruptedException; those will be handled in specific
// callback to eventually throw a OperationException, that will be used to drive the state machine in the right direction.
//
- protected <ExceptionType extends Exception> OperationResult dispatchWithAccountLockAndTimeout(final WithAccountLockCallback<OperationResult, ExceptionType> callback) throws OperationException {
+ protected <ExceptionType extends Exception> OperationResult dispatchWithAccountLockAndTimeout(final WithAccountLockCallback<PluginDispatcherReturnType<OperationResult>, ExceptionType> callback) throws OperationException {
final Account account = paymentStateContext.getAccount();
logger.debug("Dispatching plugin call for account {}", account.getExternalKey());
try {
- final Callable<OperationResult> task = new CallableWithAccountLock<OperationResult, ExceptionType>(locker,
+ final Callable<PluginDispatcherReturnType<OperationResult>> task = new CallableWithAccountLock<OperationResult, ExceptionType>(locker,
account.getExternalKey(),
callback);
final OperationResult operationResult = paymentPluginDispatcher.dispatchWithTimeout(task);
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 92a5343..556fb42 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
@@ -33,6 +33,7 @@ import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.core.ProcessorBase.WithAccountLockCallback;
import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.dispatcher.PluginDispatcher;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.payment.plugin.api.PaymentPluginApiException;
import org.killbill.billing.payment.plugin.api.PaymentPluginStatus;
@@ -133,10 +134,11 @@ public abstract class PaymentOperation extends OperationCallbackBase implements
}
private OperationResult doOperationCallbackWithDispatchAndAccountLock() throws OperationException {
- return dispatchWithAccountLockAndTimeout(new WithAccountLockCallback<OperationResult, OperationException>() {
+ return dispatchWithAccountLockAndTimeout(new WithAccountLockCallback<PluginDispatcherReturnType<OperationResult>, OperationException>() {
@Override
- public OperationResult doOperation() throws OperationException {
- return doSimpleOperationCallback();
+ public PluginDispatcherReturnType<OperationResult> doOperation() throws OperationException {
+ final OperationResult result = doSimpleOperationCallback();
+ return PluginDispatcher.createPluginDispatcherReturnType(result);
}
});
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCompletionOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCompletionOperationCallback.java
index 7d102d6..91e1f92 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCompletionOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryCompletionOperationCallback.java
@@ -26,6 +26,7 @@ import org.killbill.billing.payment.core.PaymentProcessor;
import org.killbill.billing.payment.core.ProcessorBase.WithAccountLockCallback;
import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.dispatcher.PluginDispatcher;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
import org.killbill.billing.retry.plugin.api.PaymentControlContext;
import org.killbill.billing.retry.plugin.api.PaymentControlPluginApi;
import org.killbill.commons.locker.GlobalLocker;
@@ -39,9 +40,9 @@ public class RetryCompletionOperationCallback extends RetryOperationCallback {
@Override
public OperationResult doOperationCallback() throws OperationException {
- return dispatchWithAccountLockAndTimeout(new WithAccountLockCallback<OperationResult, OperationException>() {
+ return dispatchWithAccountLockAndTimeout(new WithAccountLockCallback<PluginDispatcherReturnType<OperationResult>, OperationException>() {
@Override
- public OperationResult doOperation() throws OperationException {
+ public PluginDispatcherReturnType<OperationResult> doOperation() throws OperationException {
final PaymentTransactionModelDao transaction = paymentStateContext.getPaymentTransactionModelDao();
final PaymentControlContext updatedPaymentControlContext = new DefaultPaymentControlContext(paymentStateContext.getAccount(),
paymentStateContext.getPaymentMethodId(),
@@ -60,7 +61,7 @@ public class RetryCompletionOperationCallback extends RetryOperationCallback {
paymentStateContext.callContext);
onCompletion(retryablePaymentStateContext.getPluginName(), updatedPaymentControlContext);
- return OperationResult.SUCCESS;
+ return PluginDispatcher.createPluginDispatcherReturnType(OperationResult.SUCCESS);
}
});
}
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 3718fd5..d73d022 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
@@ -40,6 +40,7 @@ import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.core.PaymentProcessor;
import org.killbill.billing.payment.core.ProcessorBase.WithAccountLockCallback;
import org.killbill.billing.payment.dispatcher.PluginDispatcher;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
import org.killbill.billing.retry.plugin.api.FailureCallResult;
import org.killbill.billing.retry.plugin.api.PaymentControlApiException;
import org.killbill.billing.retry.plugin.api.PaymentControlContext;
@@ -75,10 +76,10 @@ public abstract class RetryOperationCallback extends OperationCallbackBase imple
@Override
public OperationResult doOperationCallback() throws OperationException {
- return dispatchWithAccountLockAndTimeout(new WithAccountLockCallback<OperationResult, OperationException>() {
+ return dispatchWithAccountLockAndTimeout(new WithAccountLockCallback<PluginDispatcherReturnType<OperationResult>, OperationException>() {
@Override
- public OperationResult doOperation() throws OperationException {
+ public PluginDispatcherReturnType<OperationResult> doOperation() throws OperationException {
final PaymentControlContext paymentControlContext = new DefaultPaymentControlContext(paymentStateContext.getAccount(),
paymentStateContext.getPaymentMethodId(),
@@ -98,7 +99,7 @@ public abstract class RetryOperationCallback extends OperationCallbackBase imple
pluginResult = getPluginResult(retryablePaymentStateContext.getPluginName(), paymentControlContext);
if (pluginResult.isAborted()) {
// Transition to ABORTED
- return OperationResult.EXCEPTION;
+ return PluginDispatcher.createPluginDispatcherReturnType(OperationResult.EXCEPTION);
}
} catch (PaymentControlApiException e) {
// Transition to ABORTED and throw PaymentControlApiException to caller.
@@ -136,7 +137,7 @@ public abstract class RetryOperationCallback extends OperationCallbackBase imple
paymentStateContext.callContext);
onCompletion(retryablePaymentStateContext.getPluginName(), updatedPaymentControlContext);
- return OperationResult.SUCCESS;
+ return PluginDispatcher.createPluginDispatcherReturnType(OperationResult.SUCCESS);
} else {
throw new OperationException(null, getOperationResultAndSetContext(retryablePaymentStateContext, paymentControlContext));
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/dispatcher/PluginDispatcher.java b/payment/src/main/java/org/killbill/billing/payment/dispatcher/PluginDispatcher.java
index 519107e..dd1ba05 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dispatcher/PluginDispatcher.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dispatcher/PluginDispatcher.java
@@ -25,6 +25,11 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import org.killbill.billing.platform.profiling.Profiling;
+import org.killbill.billing.platform.profiling.ProfilingData;
+
+import com.google.common.base.Preconditions;
+
public class PluginDispatcher<ReturnType> {
private final TimeUnit DEEFAULT_PLUGIN_TIMEOUT_UNIT = TimeUnit.SECONDS;
@@ -38,13 +43,56 @@ public class PluginDispatcher<ReturnType> {
}
// TODO Once we switch fully to automata, should this throw PaymentPluginApiException instead?
- public ReturnType dispatchWithTimeout(final Callable<ReturnType> task) throws TimeoutException, ExecutionException, InterruptedException {
+ public ReturnType dispatchWithTimeout(final Callable<PluginDispatcherReturnType<ReturnType>> task) throws TimeoutException, ExecutionException, InterruptedException {
return dispatchWithTimeout(task, timeoutSeconds, DEEFAULT_PLUGIN_TIMEOUT_UNIT);
}
- public ReturnType dispatchWithTimeout(final Callable<ReturnType> task, final long timeout, final TimeUnit unit)
+ public ReturnType dispatchWithTimeout(final Callable<PluginDispatcherReturnType<ReturnType>> task, final long timeout, final TimeUnit unit)
throws TimeoutException, ExecutionException, InterruptedException {
- final Future<ReturnType> future = executor.submit(task);
- return future.get(timeout, unit);
+
+ final Future<PluginDispatcherReturnType<ReturnType>> future = executor.submit(task);
+ final PluginDispatcherReturnType<ReturnType> pluginDispatcherResult = future.get(timeout, unit);
+
+ if (pluginDispatcherResult instanceof WithProfilingPluginDispatcherReturnType) {
+ // Transfer state from dispatch thread into current one.
+ final ProfilingData currentThreadProfilingData = Profiling.getPerThreadProfilingData();
+ if (currentThreadProfilingData != null) {
+ currentThreadProfilingData.merge(((WithProfilingPluginDispatcherReturnType)pluginDispatcherResult).getProfilingData());
+ }
+ }
+ return pluginDispatcherResult.getReturnType();
+ }
+
+ public interface PluginDispatcherReturnType<ReturnType> {
+ public ReturnType getReturnType();
+ }
+
+ public interface WithProfilingPluginDispatcherReturnType<ReturnType> extends PluginDispatcherReturnType<ReturnType> {
+ public ProfilingData getProfilingData();
}
+
+ public static class DefaultWithProfilingPluginDispatcherReturnType<ReturnType> implements WithProfilingPluginDispatcherReturnType<ReturnType> {
+ private final ReturnType returnType;
+ private final ProfilingData profilingData;
+
+ public DefaultWithProfilingPluginDispatcherReturnType(final ReturnType returnType, final ProfilingData profilingData) {
+ this.returnType = returnType;
+ this.profilingData = profilingData;
+ }
+
+ @Override
+ public ReturnType getReturnType() {
+ return returnType;
+ }
+
+ @Override
+ public ProfilingData getProfilingData() {
+ return profilingData;
+ }
+ }
+
+ public static <ReturnType> PluginDispatcherReturnType<ReturnType> createPluginDispatcherReturnType(final ReturnType returnType) {
+ return new DefaultWithProfilingPluginDispatcherReturnType(returnType, Profiling.getPerThreadProfilingData());
+ }
+
}
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 744a571..c7cf91f 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
@@ -20,8 +20,11 @@ package org.killbill.billing.payment.glue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import javax.inject.Provider;
@@ -52,6 +55,7 @@ import org.killbill.billing.payment.retry.DefaultRetryService;
import org.killbill.billing.payment.retry.DefaultRetryService.DefaultRetryServiceScheduler;
import org.killbill.billing.payment.retry.RetryService;
import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.platform.profiling.WithProfilingThreadPoolExecutor;
import org.killbill.billing.retry.plugin.api.PaymentControlPluginApi;
import org.killbill.billing.util.config.PaymentConfig;
import org.killbill.billing.util.glue.KillBillModule;
@@ -136,6 +140,22 @@ public class PaymentModule extends KillBillModule {
}
protected void installProcessors(final PaymentConfig paymentConfig) {
+
+
+ final ExecutorService pluginExecutorService = new WithProfilingThreadPoolExecutor(paymentConfig.getPaymentPluginThreadNb(), paymentConfig.getPaymentPluginThreadNb(),
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<Runnable>(),
+ new ThreadFactory() {
+
+ @Override
+ public Thread newThread(final Runnable r) {
+ final Thread th = new Thread(r);
+ th.setName(PLUGIN_THREAD_PREFIX + th.getId());
+ return th;
+ }
+ });
+
+ /*
final ExecutorService pluginExecutorService = Executors.newFixedThreadPool(paymentConfig.getPaymentPluginThreadNb(), new ThreadFactory() {
@Override
@@ -145,6 +165,9 @@ public class PaymentModule extends KillBillModule {
return th;
}
});
+ */
+
+
bind(ExecutorService.class).annotatedWith(Names.named(PLUGIN_EXECUTOR_NAMED)).toInstance(pluginExecutorService);
bind(PaymentProcessor.class).asEagerSingleton();
bind(PluginControlledPaymentProcessor.class).asEagerSingleton();
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPluginOperation.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPluginOperation.java
index 007c1f0..0c9bb88 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPluginOperation.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPluginOperation.java
@@ -38,11 +38,16 @@ import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.core.ProcessorBase.WithAccountLockCallback;
import org.killbill.billing.payment.dispatcher.PluginDispatcher;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
import org.killbill.billing.payment.plugin.api.PaymentPluginApiException;
import org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin;
+import org.killbill.billing.platform.profiling.Profiling;
+import org.killbill.billing.platform.profiling.ProfilingData.ProfilingDataOutput;
import org.killbill.commons.locker.GlobalLocker;
import org.killbill.commons.locker.memory.MemoryGlobalLocker;
import org.mockito.Mockito;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -55,8 +60,11 @@ public class TestPluginOperation extends PaymentTestSuiteNoDB {
private final GlobalLocker locker = new MemoryGlobalLocker();
private final Account account = Mockito.mock(Account.class);
+ private static final Logger logger = LoggerFactory.getLogger(TestPluginOperation.class);
+
@BeforeMethod(groups = "fast")
- public void setUp() throws Exception {
+ public void beforeMethod() throws Exception {
+ super.beforeMethod();
Mockito.when(account.getExternalKey()).thenReturn(UUID.randomUUID().toString());
}
@@ -198,7 +206,7 @@ public class TestPluginOperation extends PaymentTestSuiteNoDB {
return new PluginOperationTest(daoHelper, locker, paymentPluginDispatcher, paymentStateContext);
}
- private static final class CallbackTest implements WithAccountLockCallback<OperationResult, PaymentApiException> {
+ private static final class CallbackTest implements WithAccountLockCallback<PluginDispatcherReturnType<OperationResult>, PaymentApiException> {
private final AtomicInteger runCount = new AtomicInteger(0);
@@ -232,7 +240,7 @@ public class TestPluginOperation extends PaymentTestSuiteNoDB {
}
@Override
- public OperationResult doOperation() throws PaymentApiException {
+ public PluginDispatcherReturnType<OperationResult> doOperation() throws PaymentApiException {
try {
if (available != null) {
available.acquire();
@@ -257,8 +265,7 @@ public class TestPluginOperation extends PaymentTestSuiteNoDB {
available.release();
}
}
-
- return null;
+ return PluginDispatcher.createPluginDispatcherReturnType(null);
}
public int getRunCount() {
diff --git a/payment/src/test/java/org/killbill/billing/payment/dispatcher/TestPluginDispatcher.java b/payment/src/test/java/org/killbill/billing/payment/dispatcher/TestPluginDispatcher.java
index e3fc071..d226d73 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dispatcher/TestPluginDispatcher.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dispatcher/TestPluginDispatcher.java
@@ -22,10 +22,10 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import org.killbill.automaton.OperationException;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.payment.PaymentTestSuiteNoDB;
import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -37,9 +37,9 @@ public class TestPluginDispatcher extends PaymentTestSuiteNoDB {
public void testDispatchWithTimeout() throws TimeoutException, PaymentApiException {
boolean gotIt = false;
try {
- voidPluginDispatcher.dispatchWithTimeout(new Callable<Void>() {
+ voidPluginDispatcher.dispatchWithTimeout(new Callable<PluginDispatcherReturnType<Void>>() {
@Override
- public Void call() throws Exception {
+ public PluginDispatcherReturnType<Void> call() throws Exception {
Thread.sleep(1000);
return null;
}
@@ -59,9 +59,9 @@ public class TestPluginDispatcher extends PaymentTestSuiteNoDB {
public void testDispatchWithPaymentApiException() throws TimeoutException, PaymentApiException {
boolean gotIt = false;
try {
- voidPluginDispatcher.dispatchWithTimeout(new Callable<Void>() {
+ voidPluginDispatcher.dispatchWithTimeout(new Callable<PluginDispatcherReturnType<Void>>() {
@Override
- public Void call() throws Exception {
+ public PluginDispatcherReturnType<Void> call() throws Exception {
throw new PaymentApiException(ErrorCode.PAYMENT_ADD_PAYMENT_METHOD, "foo", "foo");
}
}, 100, TimeUnit.MILLISECONDS);
@@ -84,9 +84,9 @@ public class TestPluginDispatcher extends PaymentTestSuiteNoDB {
public void testDispatchWithRuntimeException() throws TimeoutException, PaymentApiException {
boolean gotIt = false;
try {
- voidPluginDispatcher.dispatchWithTimeout(new Callable<Void>() {
+ voidPluginDispatcher.dispatchWithTimeout(new Callable<PluginDispatcherReturnType<Void>>() {
@Override
- public Void call() throws Exception {
+ public PluginDispatcherReturnType<Void> call() throws Exception {
throw new RuntimeException("whatever");
}
}, 100, TimeUnit.MILLISECONDS);
diff --git a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java
index f80693e..4df4fbd 100644
--- a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java
@@ -34,6 +34,7 @@ import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.payment.provider.MockPaymentProviderPlugin;
import org.killbill.billing.payment.retry.DefaultRetryService;
import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.platform.profiling.Profiling;
import org.killbill.billing.util.config.PaymentConfig;
import org.killbill.bus.api.PersistentBus;
import org.testng.annotations.AfterMethod;
@@ -93,6 +94,7 @@ public abstract class PaymentTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
@BeforeMethod(groups = "fast")
public void beforeMethod() throws Exception {
eventBus.start();
+ Profiling.resetPerThreadProfilingData();
}
@AfterMethod(groups = "fast")
diff --git a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
index 0f78ff0..05b20bd 100644
--- a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
@@ -31,6 +31,7 @@ import org.killbill.billing.payment.glue.TestPaymentModuleWithEmbeddedDB;
import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.payment.provider.MockPaymentProviderPlugin;
import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.platform.profiling.Profiling;
import org.killbill.billing.util.config.PaymentConfig;
import org.killbill.bus.api.PersistentBus;
import org.testng.annotations.AfterMethod;
@@ -84,6 +85,8 @@ public abstract class PaymentTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
public void beforeMethod() throws Exception {
super.beforeMethod();
eventBus.start();
+ Profiling.resetPerThreadProfilingData();
+
}
@AfterMethod(groups = "slow")
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index ab02c64..58c601b 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.7.18</version>
+ <version>0.7.19-SNAPSHOT</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.11.8-SNAPSHOT</version>
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/KillbillGuiceListener.java b/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/KillbillGuiceListener.java
index 5304e7a..1211004 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/KillbillGuiceListener.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/listeners/KillbillGuiceListener.java
@@ -25,6 +25,7 @@ import org.killbill.billing.jaxrs.util.KillbillEventHandler;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.platform.config.DefaultKillbillConfigSource;
import org.killbill.billing.server.modules.KillbillServerModule;
+import org.killbill.billing.server.profiling.ProfilingFilter;
import org.killbill.billing.server.security.TenantFilter;
import org.killbill.bus.api.PersistentBus;
import org.killbill.commons.skeleton.modules.BaseServerModuleBuilder;
@@ -53,9 +54,11 @@ public class KillbillGuiceListener extends KillbillPlatformGuiceListener {
builder.addFilter("/*", TenantFilter.class);
}
+ builder.addFilter("/*", ProfilingFilter.class);
return builder.build();
}
+
@Override
protected Module getModule(final ServletContext servletContext) {
return new KillbillServerModule(servletContext, config, configSource);
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
index 8d19409..8ff2d63 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
@@ -66,6 +66,7 @@ import org.killbill.billing.util.glue.CustomFieldModule;
import org.killbill.billing.util.glue.ExportModule;
import org.killbill.billing.util.glue.GlobalLockerModule;
import org.killbill.billing.util.glue.KillBillShiroAopModule;
+import org.killbill.billing.util.glue.KillbillApiAopModule;
import org.killbill.billing.util.glue.NonEntityDaoModule;
import org.killbill.billing.util.glue.RecordIdModule;
import org.killbill.billing.util.glue.SecurityModule;
@@ -135,6 +136,7 @@ public class KillbillServerModule extends KillbillPlatformModule {
install(new ExportModule(configSource));
install(new GlobalLockerModule(embeddedDB.getDBEngine(), configSource));
install(new KillBillShiroAopModule());
+ install(new KillbillApiAopModule());
install(new KillBillShiroWebModule(servletContext, skifeConfigSource));
install(new NonEntityDaoModule(configSource));
install(new PaymentModule(configSource));
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/profiling/ProfilingFilter.java b/profiles/killbill/src/main/java/org/killbill/billing/server/profiling/ProfilingFilter.java
new file mode 100644
index 0000000..e6bc5df
--- /dev/null
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/profiling/ProfilingFilter.java
@@ -0,0 +1,72 @@
+/*
+ * 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.server.profiling;
+
+import java.io.IOException;
+
+import javax.inject.Singleton;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.killbill.billing.platform.profiling.Profiling;
+import org.killbill.billing.platform.profiling.ProfilingData.ProfilingDataOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class ProfilingFilter implements Filter {
+
+ private final static Logger logger = LoggerFactory.getLogger(ProfilingFilter.class);
+
+ private final static String PROFILING_HEADER_REQ = "X-Killbill-Profiling-Req";
+ private final static String PROFILING_HEADER_RESP = "X-Killbill-Profiling-Resp";
+
+ @Override
+ public void init(final FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
+
+ final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+ final String profilingHeaderRequest = httpServletRequest.getHeader(PROFILING_HEADER_REQ);
+ if (profilingHeaderRequest != null) {
+ try {
+ final ProfilingDataOutput profilingOutput = ProfilingDataOutput.valueOf(profilingHeaderRequest);
+ Profiling.setPerThreadProfilingData(profilingOutput);
+ } catch (IllegalArgumentException e) {
+ logger.info("Profiling data output " + profilingHeaderRequest + " is not supported, profiling NOT enabled");
+ }
+ }
+ try {
+ filterChain.doFilter(servletRequest, servletResponse);
+ } finally {
+ Profiling.resetPerThreadProfilingData();
+ }
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+}
diff --git a/profiles/killbill/src/main/resources/killbill-server.properties b/profiles/killbill/src/main/resources/killbill-server.properties
index 1c6344d..2eeabec 100644
--- a/profiles/killbill/src/main/resources/killbill-server.properties
+++ b/profiles/killbill/src/main/resources/killbill-server.properties
@@ -20,6 +20,7 @@
org.killbill.dao.url=jdbc:mysql://127.0.0.1:3306/killbill
org.killbill.dao.user=root
org.killbill.dao.password=root
+org.killbill.dao.logLevel=DEBUG
org.killbill.billing.osgi.dao.url=jdbc:mysql://127.0.0.1:3306/killbill
org.killbill.billing.osgi.dao.user=root
org.killbill.billing.osgi.dao.password=root
diff --git a/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java b/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java
index 205e680..fed4c77 100644
--- a/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java
+++ b/profiles/killpay/src/main/java/org/killbill/billing/server/modules/KillpayServerModule.java
@@ -52,6 +52,7 @@ import org.killbill.billing.util.glue.CustomFieldModule;
import org.killbill.billing.util.glue.ExportModule;
import org.killbill.billing.util.glue.GlobalLockerModule;
import org.killbill.billing.util.glue.KillBillShiroAopModule;
+import org.killbill.billing.util.glue.KillbillApiAopModule;
import org.killbill.billing.util.glue.NonEntityDaoModule;
import org.killbill.billing.util.glue.RecordIdModule;
import org.killbill.billing.util.glue.SecurityModule;
@@ -75,6 +76,7 @@ public class KillpayServerModule extends KillbillServerModule {
install(new ExportModule(configSource));
install(new GlobalLockerModule(embeddedDB.getDBEngine(), configSource));
install(new KillBillShiroAopModule());
+ install(new KillbillApiAopModule());
install(new KillBillShiroWebModule(servletContext, skifeConfigSource));
install(new NonEntityDaoModule(configSource));
install(new PaymentModule(configSource));
util/pom.xml 4(+4 -0)
diff --git a/util/pom.xml b/util/pom.xml
index 3dbf8f7..a69c56d 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -134,6 +134,10 @@
</dependency>
<dependency>
<groupId>org.kill-bill.billing</groupId>
+ <artifactId>killbill-platform-base</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.kill-bill.billing</groupId>
<artifactId>killbill-platform-osgi-api</artifactId>
<scope>test</scope>
</dependency>
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
index 456bf95..2651f2c 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
@@ -30,6 +30,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import org.killbill.billing.platform.profiling.Profiling;
+import org.killbill.billing.platform.profiling.Profiling.WithProfilingCallback;
import org.killbill.billing.util.tag.dao.UUIDCollectionBinder;
import org.skife.jdbi.v2.Binding;
import org.skife.jdbi.v2.StatementContext;
@@ -83,6 +85,7 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
private final CacheControllerDispatcher cacheControllerDispatcher;
private final Clock clock;
private final NonEntityDao nonEntityDao;
+ private final Profiling prof;
public EntitySqlDaoWrapperInvocationHandler(final Class<S> sqlDaoClass, final S sqlDao, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
this.sqlDaoClass = sqlDaoClass;
@@ -90,12 +93,18 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
this.clock = clock;
this.cacheControllerDispatcher = cacheControllerDispatcher;
this.nonEntityDao = nonEntityDao;
+ this.prof = new Profiling<Object>();
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
try {
- return invokeSafely(proxy, method, args);
+ return prof.executeWithProfiling("DAO:" + sqlDaoClass.getSimpleName() + ":" + method.getName(), new WithProfilingCallback() {
+ @Override
+ public Object execute() throws Throwable {
+ return invokeSafely(proxy, method, args);
+ }
+ });
} catch (Throwable t) {
if (t.getCause() != null && t.getCause().getCause() != null && DBIException.class.isAssignableFrom(t.getCause().getClass())) {
// Likely a JDBC error, try to extract the SQL statement and JDBI bindings
diff --git a/util/src/main/java/org/killbill/billing/util/glue/KillbillApiAopModule.java b/util/src/main/java/org/killbill/billing/util/glue/KillbillApiAopModule.java
new file mode 100644
index 0000000..ce34cc8
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/glue/KillbillApiAopModule.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util.glue;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.killbill.billing.KillbillApi;
+import org.killbill.billing.platform.profiling.Profiling;
+import org.killbill.billing.platform.profiling.Profiling.WithProfilingCallback;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.matcher.Matchers;
+
+public class KillbillApiAopModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+
+ bindInterceptor(Matchers.subclassesOf(KillbillApi.class),
+ Matchers.any(),
+ new ProfilingMethodInterceptor());
+ }
+
+ public static class ProfilingMethodInterceptor implements MethodInterceptor {
+
+ private final Profiling prof = new Profiling<Object>();
+
+ @Override
+ public Object invoke(final MethodInvocation invocation) throws Throwable {
+ return prof.executeWithProfiling("API:" + invocation.getMethod().getName(), new WithProfilingCallback() {
+ @Override
+ public Object execute() throws Throwable {
+ return invocation.proceed();
+ }
+ });
+ }
+ }
+}